CF995F拉格朗日+组合数学+DP

28. CF995F拉格朗日+组合数学+DP,1是根节点

若D=3000,有O(nD)的做法:

设DP[i][j]为点i的权值是j的方案数,答案就是sum_{i=0}^{D} dp[1][i]

Dp[u][j]=对每个邻接点v  dp[u][i]=dp[u][i]*( dp[v][j]的前缀和, j<=i)

就是说预处理1~3000 用拉格朗日插值搞第d项

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=1e9+7;
int dp[3005][3005];
int fa[3005];
ll pre[3005];
vector<int>vs[3005];
void dfs(int u,int d)
{
    for(int i=1;i<=d;i++)dp[u][i]=1;
    for(int j=0;j<vs[u].size();j++)
    {
        int v=vs[u][j];
        dfs(v,d);
        for(int i=1;i<=d;i++)pre[i]=dp[v][i];
        for(int i=1;i<=d;i++)(pre[i]+=pre[i-1])%=mod;
        for(int i=1;i<=d;i++)dp[u][i]=1ll*dp[u][i]*pre[i]%mod;//乘上所有邻接点的前缀和 
    }
}
namespace polysum {
    #define rep(i,a,n) for (int i=a;i<n;i++)
    #define per(i,a,n) for (int i=n-1;i>=a;i--)
    
    const int D=101000;
    ll a[D],tmp[D],f[D],g[D],p[D],p1[D],p2[D],b[D],h[D][2],C[D];
    ll powmod(ll a,ll b){ll res=1;a%=mod;assert(b>=0);for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
    ll calcn(int d,ll *a,ll n) { // 预处理a[0].. a[d]  得到a[n] 
        if (n<=d) return a[n];
        p1[0]=p2[0]=1;
        rep(i,0,d+1) {
            ll t=(n-i+mod)%mod;
            p1[i+1]=p1[i]*t%mod;
        }
        rep(i,0,d+1) {
            ll t=(n-d+i+mod)%mod;
            p2[i+1]=p2[i]*t%mod;
        }
        ll ans=0;
        rep(i,0,d+1) {
            ll t=g[i]*g[d-i]%mod*p1[i]%mod*p2[d-i]%mod*a[i]%mod;
            if ((d-i)&1) ans=(ans-t+mod)%mod;
            else ans=(ans+t)%mod;
        }
        return ans;
    }
    void init(int M) {//预处理阶乘&&阶乘的逆元 
        f[0]=f[1]=g[0]=g[1]=1;
        rep(i,2,M+5) f[i]=f[i-1]*i%mod;
        g[M+4]=powmod(f[M+4],mod-2);
        per(i,1,M+4) g[i]=g[i+1]*(i+1)%mod;
    }
    ll polysum(ll n,ll *a,ll m) { // 预处理a[0].. a[m] 得到\sum_{i=0}^{n-1} a[i] 
        rep(i,0,m+1) tmp[i]=a[i];
        tmp[m+1]=calcn(m,tmp,m+1);
        rep(i,1,m+2) tmp[i]=(tmp[i-1]+tmp[i])%mod;
        return calcn(m+1,tmp,n-1);
    }
    ll qpolysum(ll R,ll n,ll *a,ll m) { // a[0].. a[m] \sum_{i=0}^{n-1} a[i]*R^i
        if (R==1) return polysum(n,a,m);
        a[m+1]=calcn(m,a,m+1);
        ll r=powmod(R,mod-2),p3=0,p4=0,c,ans;
        h[0][0]=0;h[0][1]=1;
        rep(i,1,m+2) {
            h[i][0]=(h[i-1][0]+a[i-1])*r%mod;
            h[i][1]=h[i-1][1]*r%mod;
        }
        rep(i,0,m+2) {
            ll t=g[i]*g[m+1-i]%mod;
            if (i&1) p3=((p3-h[i][0]*t)%mod+mod)%mod,p4=((p4-h[i][1]*t)%mod+mod)%mod;
            else p3=(p3+h[i][0]*t)%mod,p4=(p4+h[i][1]*t)%mod;
        }
        c=powmod(p4,mod-2)*(mod-p3)%mod;
        rep(i,0,m+2) h[i][0]=(h[i][0]+h[i][1]*c)%mod;
        rep(i,0,m+2) C[i]=h[i][0];
        ans=(calcn(m,C,n)*powmod(R,n)-c)%mod;
        if (ans<0) ans+=mod;
        return ans;
    }
} // polysum::init();
int main()
{
    memset(pre,0,sizeof(pre));
    int n,d;scanf("%d %d",&n,&d);int x;
    for(int i=2;i<=n;i++)
        scanf("%d",&x),vs[x].push_back(i);
    dfs(1,n);
    
    for(int i=0;i<=n;i++)pre[i]=dp[1][i];
    for(int i=1;i<=n;i++)(pre[i]+=pre[i-1])%=mod;
    polysum::init(3455);
    printf("%lld\n",polysum::calcn(n,pre,d)%mod); 
        //printf("i:%d %d\n",i,dp[1][i]);
} 

猜你喜欢

转载自blog.csdn.net/animalcoder/article/details/82504897
今日推荐