bzoj2159 Crash 的文明世界 第二类斯特林数+树形dp

版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/85196217

Description


Crash 小朋友最近迷上了一款游戏——文明5(Civilization V)。在这个游戏中,玩家可以建立和发展自己的国家,通过外交和别的国家交流,或是通过战争征服别的国家。现在Crash 已经拥有了一个N 个城市的国家,这些城市之间通过道路相连。由于建设道路是有花费的,因此Crash 只修建了N-1 条道路连接这些城市,不过可以保证任意两个城市都有路径相通。在游戏中,Crash 需要选择一个城市作为他的国家的首都,选择首都需要考虑很多指标,有一个指标是这样的: 其中S(i)表示第i 个城市的指标值,dist(i, j)表示第i 个城市到第j 个城市需要经过的道路条数的最小值,k 为一个常数且为正整数。因此Crash 交给你一个简单的任务:给出城市之间的道路,对于每个城市,输出这个城市的指标值,由于指标值可能会很大,所以你只需要输出这个数mod 10007 的值。
S ( i ) = j = 1 n d i s t ( i , j ) k S(i)=\sum_{j=1}^n {dist(i,j)}^k

Solution


这种指数很小的次幂可以套路地转化成组合数问题,即有 n k = i = 0 k { k i } ( n i ) i ! n^k=\sum_{i=0}^k \begin{Bmatrix}k\\i\end{Bmatrix}\binom{n}{i}i!
考虑两边柿子的组合数含义。左边即n个有标号的球放进k个有标号的盒子,盒子可以为空的方案数。右边则是我们枚举几个盒子非空。
然后就可以根据杨辉三角形的性质dp了。设f[i,j]表示i子树内的点x到i的 ( d i s t ( i , x ) j ) \binom{dist(i,x)}{j} 的和,g[i,j]表示除i的子树外对i的贡献,两次dfs转移就没了

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

const int MOD=10007;
const int N=50005;
const int M=155;

struct edge {int y,next;} e[N*2];

int f[N][M],g[N][M],s[M][M];
int ls[N],fac[M],edCnt;
int n,k;

void add_edge(int x,int y) {
	e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
	e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}

void dfs1(int now,int fa) {
	f[now][0]=1;
	for (int i=ls[now];i;i=e[i].next) {
		if (e[i].y==fa) continue;
		dfs1(e[i].y,now);
		f[now][0]=(f[now][0]+f[e[i].y][0])%MOD;
		rep(j,1,k) f[now][j]=(f[now][j]+f[e[i].y][j]+f[e[i].y][j-1])%MOD;
	}
}

void dfs2(int now,int fa) {
	g[now][0]=(n-f[now][0]);
	if (fa) {
		rep(i,1,k) {
			g[now][i]+=g[fa][i]+g[fa][i-1];
			g[now][i]+=f[fa][i]+f[fa][i-1];
			g[now][i]-=f[now][i]+f[now][i-1];
			g[now][i]-=f[now][i-1];
			if (i>1) g[now][i]-=f[now][i-2];
			g[now][i]=(g[now][i]%MOD+MOD)%MOD;
		}
	}
	for (int i=ls[now];i;i=e[i].next) {
		if (e[i].y==fa) continue;
		dfs2(e[i].y,now);
	}
}

void read1() {
	int L,now,A,B,Q,tmp;
	scanf("%d%d%d",&n,&k,&L);
	scanf("%d%d%d%d",&now,&A,&B,&Q);
	rep(i,1,n-1) {
		now=(now*A+B)%Q;
		tmp=(i<L)?i:L;
		add_edge(i-now%tmp,i+1);
	} 
}

void read2() {
	scanf("%d%d",&n,&k);
	rep(i,2,n) {
		int x,y; scanf("%d%d",&x,&y);
		add_edge(x,y);
	}
}

int main(void) {
	//read1();
	read2();
	s[1][1]=1;
	rep(i,2,k) rep(j,1,k) s[i][j]=(s[i-1][j]*j+s[i-1][j-1])%MOD;
	fac[0]=1; rep(i,1,k) fac[i]=fac[i-1]*i%MOD;
	dfs1(1,0); dfs2(1,0);
	rep(i,1,n) {
		int ans=0;
		rep(j,1,k) {
			ans+=(f[i][j]+g[i][j])*s[k][j]%MOD*fac[j]%MOD;
			(ans>=MOD)?(ans-=MOD):0;
		}
		printf("%d\n", ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/85196217