BZOJ 2159: Crash 的文明世界(組合數學+第二類斯特林數+樹形dp)
阿新 • • 發佈:2018-11-23
解題思路
比較有意思的一道數學題。首先\(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; }