BZOJ 2159: Crash 的文明世界(组合数学+第二类斯特林数+树形dp)

传送门

解题思路

  比较有意思的一道数学题。首先\(n*k^2\)的做法比较好想,就是维护一个\(x^i\)这种东西,然后转移的时候用二项式定理拆开转移。然后有一个比较有意思的结论就是把求\(x^i\)这种东西变成组合数去求,具体来说就是\(n^k=\sum\limits_{i=1}^k\dbinom{n}{i}*S[k][i]*i!\)\(S\)表示第二类斯特林数,第二类斯特林数可以表示为有\(n\)个盒子要装\(m\)个小球,然后在给盒子和求加上编号就可以得出上面的式子。这样的话在根据帕斯卡三角,每个组合数只会被两个组合数递推出来,所以就能\(O(nk)\)的维护了。参考了这位大佬的博客:https://blog.csdn.net/Mys_C_K/article/details/79942486?utm_source=blogxgwz3

代码

#include<iostream>
#include<cstdio>
#include<cstring>
 
using namespace std;
const int MAXN = 50005;
const int MOD = 10007;
typedef long long LL;
 
inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return f?x:-x;
}
 
int n,head[MAXN],cnt,to[MAXN<<1],nxt[MAXN<<1],ans[MAXN];
int s[155][155],k,fac[MAXN],f[MAXN][155],g[MAXN][155];
 
inline void add(int bg,int ed){
    to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt;
}
 
inline int calc(int x,int y,int k){
    return (g[x][k]-f[y][k]-(k>0?f[y][k-1]:0)+2*MOD)%MOD;
}
 
void prework(){
    fac[1]=1;s[0][0]=1;
    for(int i=2;i<=k;i++) fac[i]=fac[i-1]*i%MOD;
    for(int i=1;i<=k;i++)
        for(int j=1;j<=i;j++)
            (s[i][j]=s[i-1][j-1]+j*s[i-1][j]%MOD)%=MOD;
}
 
void dfs1(int x,int fa){
    f[x][0]=1;int u;
    for(int i=head[x];i;i=nxt[i]){
        u=to[i];if(u==fa) continue;dfs1(u,x);f[x][0]+=f[u][0];f[x][0]%=MOD;
        for(int j=1;j<=k;j++)
            f[x][j]+=f[u][j]+f[u][j-1],f[x][j]=f[x][j]>=MOD?f[x][j]-MOD:f[x][j];
    }
}
 
void dfs2(int x,int fa){
    for(int i=0;i<=k;i++) g[x][i]+=f[x][i],g[x][i]%=MOD;
    int u;
    for(int i=head[x];i;i=nxt[i]){
        u=to[i];if(u==fa) continue;
        g[u][0]=g[x][0]-f[u][0];
        for(int i=1;i<=k;i++)
            g[u][i]=calc(x,u,i)+calc(x,u,i-1),g[u][i]%=MOD;
        dfs2(u,x);
    }
}
 
int main(){
    int now,A,B,Q,L,tmp,x,y;
    n=rd(),k=rd(),L=rd(),now=rd(),A=rd(),B=rd(),Q=rd();
    for (int i=1;i<n;i++) {
        now=(now*A+B)%Q;
        tmp=i<L?i:L;x=i-now%tmp,y=i+1; 
        add(x,y),add(y,x); 
    }
    prework();dfs1(1,0);dfs2(1,0);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=k;j++)
            ans[i]=(ans[i]+(LL)fac[j]*g[i][j]%MOD*s[k][j]%MOD)%MOD;
    for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
    return 0;
}
posted @ 2018-11-23 20:39  Monster_Qi  阅读(117)  评论(0编辑  收藏  举报