题目传送门:ARC121E Directed Tree。
首先,如果 \(i\) 满足条件,那么 \(a_i\) 不为 \(i\) 的祖先(注意 \(a_i=i\) 满足条件),设 \(g_i\) 表示钦定 \(i\) 个位置不满足的方案数。
考虑 dp,设 \(f_{i,j}\) 表示以 \(i\) 为根的子树,钦定了 \(j\) 个位置且只考虑这 \(j\) 个位置的方案数。
转移分两种情况。
- 从儿子转移 \(f_{u,i}\times f_{v,j} \to f'_{u,i+j}\)。
- 在 \(u\) 的子树中找一个位置钦定且 \(a\) 为 \(u\),\(f_{u,i-1}\times [(sz_u-1)-(i-1)] \to f'_{u,i}\)。
因此 \(g_i=f_{1,i}\times (n-i)!\),没钦定的可以随便选。
最后答案直接二项式反演 \(ans=\sum_{i=0}^n (-1)^ig_i\)。
注意转移时枚举的顺序,具体的看代码。
#include<bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
const int N=2010,mod=998244353;
inline int read(){char c=getchar();int f=1,ans=0;while(c<48||c>57) f=(c==45?f=-1:1),c=getchar();while(c>=48&&c<=57) ans=(ans<<1)+(ans<<3)+(c^48),c=getchar();return ans*f;
}
int n;vector<int>g[N];
int f[N][N],jc[N],tmp[N],sz[N];
void dfs(int u){f[u][0]=sz[u]=1;for (auto v:g[u]){dfs(v);for (int i=0;i<=sz[u]+sz[v];i++) tmp[i]=0;for (int i=0;i<=sz[u];i++) for (int j=0;j<=sz[v];j++) if (i+j<=n) tmp[i+j]=(tmp[i+j]+f[u][i]*f[v][j]%mod)%mod;for (int i=0;i<=sz[u]+sz[v];i++) f[u][i]=tmp[i];sz[u]+=sz[v];}for (int i=sz[u];i;i--) f[u][i]=(f[u][i]+f[u][i-1]*(sz[u]-i)%mod)%mod;
}
main(){n=read();for (int i=2;i<=n;i++) g[read()].push_back(i);jc[0]=1;for (int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mod;dfs(1);int ans=0;for (int i=0;i<=n;i++){if (i&1) ans=(ans-f[1][i]*jc[n-i]%mod+mod)%mod;else ans=(ans+f[1][i]*jc[n-i]%mod)%mod;}cout <<ans;return 0;
}