1. 程式人生 > >BZOJ 2159: Crash 的文明世界(組合數學+第二類斯特林數+樹形dp)

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;
}