题解:AT_agc068_d [AGC068D] Sum of Hash of Lexmin
题意:
给定一棵父亲编号小于儿子编号的树,可以交换排列中相邻且呈祖孙关系的两个点。称无法变成字典序更小的排列为合法排列,求所有合法排列的
思路:
合法等价于不存在“后代紧挨在祖先前面”。
:::info[证明]
若能变小,设首个变化位置由
初始化
合并完儿子后加入
若
答案为
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=110,mod=998244353;
int n,B,ans,sz[N],c[N][N];
int f[N][N][N][2],g[N][N][2];
vector<int> edge[N];
void add(int &x,int y){x=(x+y)%mod;}
void sub(int &x,int y){x=(x-y+mod)%mod;}
void clear(int s)
{
for(int l=0;l<=s;l++)
for(int r=0;l+r<=s;r++)
g[l][r][0]=g[l][r][1]=0;
}
void dfs(int u)
{
f[u][0][0][0]=1;
for(int v:edge[u])
{
dfs(v);
clear(sz[u]+sz[v]);
for(int l=0;l<=sz[u];l++)
for(int r=0;l+r<=sz[u];r++)
for(int t=0;t<=1;t++)
{
int x=f[u][l][r][t];
if(!x) continue;
for(int a=0;a<=sz[v];a++)
for(int b=0;a+b<=sz[v];b++)
for(int k=0;t+k<=1;k++)
{
int y=f[v][a][b][k];
if(!y) continue;
add(g[l+a][r+b][t+k],x*y%mod*c[l+a][l]%mod*c[r+b][r]);
}
}
sz[u]+=sz[v];
for(int l=0;l<=sz[u];l++)
for(int r=0;l+r<=sz[u];r++)
for(int t=0;t<=1;t++)
f[u][l][r][t]=g[l][r][t];
}
clear(sz[u]+1);
for(int l=0;l<=sz[u];l++)
for(int r=0;l+r<=sz[u];r++)
for(int t=0;t<=1;t++)
{
int x=f[u][l][r][t];
if(!x) continue;
sub(g[l][r][t],x*l%mod*B);
sub(g[l][r][t],x*r);
add(g[l+1][r][t],x*(l+1)%mod*B);
add(g[l][r+1][t],x*(r+1));
if(t) sub(g[l][r][1],x);
else
{
add(g[l][r][1],x*u);
if(l) sub(g[l-1][r][1],x*u);
}
}
sz[u]++;
for(int l=0;l<=sz[u];l++)
for(int r=0;l+r<=sz[u];r++)
for(int t=0;t<=1;t++)
f[u][l][r][t]=g[l][r][t];
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>B;
B%=mod;
for(int i=2,p;i<=n;i++)
cin>>p,edge[p].push_back(i);
c[0][0]=1;
for(int i=1;i<=n;i++)
{
c[i][0]=1;
for(int j=1;j<=i;j++)
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
dfs(1);
for(int l=0;l<n;l++)
for(int r=0;l+r<n;r++)
add(ans,f[1][l][r][1]);
cout<<ans;
return 0;
}