bzoj2159 Crash 的文明世界 树形dp

       一般这种统计里面带k次方的都要转换成组合数把。。。

       有:x^k=Σ(i=1,n) Stirling2(k,i)*P(x,i),而P(x,i)=C(x,i)*i!,这样就成功转化成组合数了。那么答案就是对于一定定点x要统计所有的Σ(i=1,n) C(dist(x,i),j) j=1...n,那么利用C(i,j)=C(i-1,j-1)+C(i-1,j),以及父亲和儿子的答案(dist刚好相差1)得到x的答案。上下dfs一遍即可。

AC代码如下:

#include<iostream>
#include<cstdio>
#define mod 10007
#define N 50005
#define M 155
using namespace std;

int n,m,tot,L,now,A,B,Q,fst[N],pnt[N<<1],nxt[N<<1],f[N][M],g[N][M],s[M][M],fac[M];
void add(int x,int y){
	pnt[++tot]=y; nxt[tot]=fst[x]; fst[x]=tot;
}
void ad(int &x,int y){ x+=y; if (x>=mod) x-=mod; }
void dl(int &x,int y){ x-=y; if (x<0) x+=mod; }
void dfs1(int x,int fa){
	int p,i; f[x][0]=1;
	for (p=fst[x]; p; p=nxt[p]){
		int y=pnt[p];
		if (y!=fa){
			dfs1(y,x); ad(f[x][0],f[y][0]);
			for (i=1; i<=m; i++) ad(f[x][i],(f[y][i]+f[y][i-1])%mod);
		}
	}
}
void dfs2(int x,int fa){
	int p,i;
	if (fa){
		g[x][0]=n-f[x][0];
		for (i=1; i<=m; i++){
			ad(g[x][i],((g[fa][i]+g[fa][i-1]+f[fa][i]+f[fa][i-1]-f[x][i]-(f[x][i-1]<<1))%mod+mod)%mod);
			if (i>1) dl(g[x][i],f[x][i-2]);
		}
	}
	for (p=fst[x]; p; p=nxt[p]) if (pnt[p]!=fa) dfs2(pnt[p],x);
}
int main(){
	scanf("%d%d%d%d%d%d%d",&n,&m,&L,&now,&A,&B,&Q); int i,j,x,y,tmp;
	for(i=1; i<n; i++){
		now=(now*A+B)%Q; tmp=min(i,L);
		x=i-now%tmp; y=i+1;
		add(x,y); add(y,x);
	}
	s[0][0]=1;
	for (i=1; i<=m; i++)
		for (j=1; j<=i; j++) s[i][j]=(s[i-1][j]*j+s[i-1][j-1])%mod;
	fac[1]=1;
	for (i=2; i<=m; i++) fac[i]=fac[i-1]*i%mod;
	dfs1(1,0); dfs2(1,0);
	for (i=1; i<=n; i++){
		x=0;
		for (j=1; j<=m; j++) ad(x,s[m][j]*fac[j]%mod*(f[i][j]+g[i][j])%mod);
		printf("%d\n",x);
	}
	return 0;
}


by lych

2016.4.23

你可能感兴趣的:(组合数学,递推,树形DP)