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

题目链接

BZOJ2159

题解

显然不能直接做点分之类的,观察式子中存在式子\(n^k\)
可以考虑到

\[n^k = \sum\limits_{i = 0} \begin{Bmatrix} k \\ i \end{Bmatrix} {n \choose i}i! \]

发现\(k\)很小,对于每个点可以直接\(O(k)\)计算
所以我们只需求出

\[f[i][j] = \sum\limits_{x = 1}^{N}{dis(i,x) \choose j} \]

转移可以利用

\[{n \choose m} = {n - 1 \choose m} + {n - 1 \choose m - 1} \]

复杂度\(O(nk + k^2)\)
最后注意一下读入是加密的,在题目末尾

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 50005,maxm = 155,INF = 1000000000,P = 10007;
int f[maxn][maxm],g[maxm],n,K,fa[maxn];
int h[maxn],ne = 1;
struct EDGE{int to,nxt;}ed[maxn << 1];
inline void build(int u,int v){
	ed[++ne] = (EDGE){v,h[u]}; h[u] = ne;
	ed[++ne] = (EDGE){u,h[v]}; h[v] = ne;
}
void dfs1(int u){
	f[u][0] = 1;
	Redge(u) if ((to = ed[k].to) != fa[u]){
		fa[to] = u; dfs1(to);
		f[u][0] = f[u][0] + f[to][0];
		for (int k = 1; k <= K; k++)
			f[u][k] = (f[u][k] + f[to][k - 1] + f[to][k]) % P;
	}
}
void dfs2(int u){
	if (fa[u]){
		int v = fa[u];
		g[0] = f[v][0] - f[u][0];
		for (int k = 1; k <= K; k++)
			g[k] = ((f[v][k] - f[u][k] - f[u][k - 1]) % P + P) % P;
		f[u][0] = n;
		for (int k = 1; k <= K; k++)
			f[u][k] = (f[u][k] + g[k] + g[k - 1]) % P;
	}
	Redge(u) if ((to = ed[k].to) != fa[u])
		dfs2(to);
}
int S[maxm][maxm],ans,fac[maxm];
void work(){
	S[0][0] = 1; fac[0] = 1;
	for (register int i = 1; i <= K; i++) fac[i] = fac[i - 1] * i % P;
	for (register int i = 1; i <= K; i++)
		for (register int j = 1; j <= i; j++)
			S[i][j] = (S[i - 1][j - 1] + j * S[i - 1][j]) % P;
	for (register int i = 1; i <= n; i++){
		ans = 0;
		for (register int k = 0; k <= K; k++)
			ans = (ans + f[i][k] * fac[k] % P * S[K][k] % P) % P;
		printf("%d\n",ans);
	}
}
void readin() {
	int L,now,A,B,Q,tmp;
	scanf("%d%d%d",&n,&K,&L);
	scanf("%d%d%d%d",&now,&A, &B, &Q);
	for (int i = 1; i < n; i++){
		now = (now * A + B) % Q; tmp = (i < L) ? i : L;
		build(i - now % tmp,i + 1);
	}
}
int main(){
	readin();
	dfs1(1);
	dfs2(1);
	work();
	return 0;
}

posted @ 2018-06-23 21:46  Mychael  阅读(164)  评论(0编辑  收藏  举报