CF995F Cowmpany Cowmpensation

Link
首先有一个很显然的\(O(nd)\)的dp,设\(f_{i,j}\)表示只考虑\(i\)的子树,\(i\)的权值\(j\)时的方案数。
转移是\(f_{i,j}=\prod\limits_{v\in son_u}\sum\limits_{k=1}^jf_{v,k}\),前缀和优化即可。
不难发现\(g_u(x)=f_{u,x}\)是一个不超过\(n\)次的多项式,因此dp时第二维的范围可以缩小至\([0,n]\)
然后Lagrange插值求出答案即可。

#include<cstdio>
const int N=3007,P=1000000007;
int fa[N],f[N][N],inv[N];
int read(){int x;scanf("%d",&x);return x;}
void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
int mul(int a,int b){return 1ll*a*b%P;}
int main()
{
    int n=read(),d=read(),ans=0;inv[1]=1;
    for(int i=2;i<=n;++i) inv[i]=mul(P-P/i,inv[P%i]);
    for(int i=2;i<=n;++i) fa[i]=read();
    for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) f[i][j]=1;
    for(int i=n;i;--i)
    {
	for(int j=1;j<n;++j) inc(f[i][j+1],f[i][j]);
	for(int j=1;j<=n;++j) f[fa[i]][j]=mul(f[fa[i]][j],f[i][j]);
    }
    for(int i=1;i<=n;++i)
    {
	int x=f[1][i];
	for(int j=0;j<=n;++j) if(i^j) x=1ll*x*(d-j+P)%P*(i>j? inv[i-j]:P-inv[j-i])%P;
	inc(ans,x);
    }
    printf("%d",ans);
}
posted @ 2020-04-15 09:26  Shiina_Mashiro  阅读(192)  评论(0编辑  收藏  举报