BZOJ2159 Crash的文明世界(树形dp+斯特林数)

  根据组合意义,有nk=ΣC(n,i)*i!*S(k,i) (i=0~k),即将k个有标号球放进n个有标号盒子的方案数=在n个盒子中选i个将k个有标号球放入并且每个盒子至少有一个球。

  回到本题,可以令f[i][j]表示ΣC(dis(i,k),j) (k为i子树中节点),通过C(i,j)=C(i-1,j)+C(i-1,j-1)转移。

 

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 50010
#define K 155
#define P 10007
int n,m,l,now,A,B,Q,tmp,p[N],t=0;
int f[N][K],S[K][K],fac[K],ans[N];
struct data{int to,nxt;
}edge[N<<1];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void dfs(int k,int from)
{
    f[k][0]=1;
    for (int i=p[k];i;i=edge[i].nxt)
    if (edge[i].to!=from)
    {
        dfs(edge[i].to,k);
        f[k][0]=(f[k][0]+f[edge[i].to][0])%P;
        for (int j=1;j<=m;j++)
        f[k][j]=(f[k][j]+f[edge[i].to][j]+f[edge[i].to][j-1])%P;
    }
}
void getans(int k,int from)
{
    for (int j=0;j<=m;j++)
    ans[k]=(ans[k]+f[k][j]*fac[j]%P*S[m][j])%P;
    for (int i=p[k];i;i=edge[i].nxt)
    if (edge[i].to!=from)
    {
        for (int j=m;j>=2;j--)
        f[edge[i].to][j]=((f[k][j]-f[edge[i].to][j-1]+f[k][j-1]-f[edge[i].to][j-1]-f[edge[i].to][j-2])%P+P)%P;
        f[edge[i].to][1]=((f[k][1]-f[edge[i].to][0]+f[k][0]-f[edge[i].to][0])%P+P)%P;
        f[edge[i].to][0]=n;
        getans(edge[i].to,k);
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj2159.in","r",stdin);
    freopen("bzoj2159.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read(),m=read(),l=read(),now=read(),A=read(),B=read(),Q=read();
    for (int i=1;i<n;i++)
    {
        now=(now*A+B)%Q;
        tmp=(i<l)?i:l;
        int x=i-now%tmp,y=i+1;
        addedge(x,y),addedge(y,x);
    }
    dfs(1,1);
    fac[0]=1;for (int i=1;i<=m;i++) fac[i]=fac[i-1]*i%P;
    S[0][0]=1;
    for (int i=1;i<=m;i++)
        for (int j=1;j<=i;j++)
        S[i][j]=(S[i-1][j-1]+S[i-1][j]*j)%P;
    getans(1,1);
    for (int i=1;i<=n;i++) printf("%d\n",ans[i]);
    return 0;
}

 

posted @ 2018-08-29 13:03  Gloid  阅读(183)  评论(0编辑  收藏  举报