# BZOJ2159：Crash 的文明世界 （第二类stirling数+组合数学+树形DP）

$20\mathrm{%}$$20\%$：直接以每个点为根DFS一遍，求出其它点的深度。预处理${1}^{k}$$1^k$~${n}^{k}$$n^k$统计答案。时间复杂度$O\left({n}^{2}+nk\right)$$O(n^2+nk)$

$50\mathrm{%}$$50\%$：令$S\left[node\right]\left[d\right]=\sum _{u\in node}dis\left(node,u{\right)}^{d}$$S[node][d]=\sum_{u\in node}dis(node,u)^d$。当计算node父亲节点fa的S值时，显然有：

$S\left[fa\right]\left[d\right]=\sum _{p=0}^{d}{C}_{d}^{p}\ast S\left[node\right]\left[p\right]$

$100\mathrm{%}$$100\%$发现计算S[fa][d]是个卷积的形式，所以用NTT优化

${d}^{k}=\sum _{p=0}^{d}{C}_{d}^{p}\ast S\left(k,p\right)\ast \left(p!\right)$

CODE：

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
using namespace std;

const int maxn=50100;
const int maxk=160;
const int M=10007;

struct edge
{
int obj;
edge *Next;
} e[maxn<<1];
int cur=-1;

int f[maxn][maxk];
int g[maxn][maxk];

int S[maxk][maxk];
int h[maxk];
int fac[maxk];

int fa[maxn];
int n,k;

{
cur++;
e[cur].obj=y;
}

void Dfs1(int node)
{
f[node][0]=1;
{
int son=p->obj;
if (son==fa[node]) continue;
fa[son]=node;
Dfs1(son);

f[node][0]=(f[node][0]+f[son][0])%M;
for (int i=1; i<=k; i++)
f[node][i]=(f[node][i]+f[son][i]+f[son][i-1])%M;
}
}

void Dfs2(int node)
{
{
int son=p->obj;
if (son==fa[node]) continue;

g[son][0]=f[node][0]-f[son][0];
for (int i=0; i<=k; i++)
g[son][i]=(f[node][i]-f[son][i]-f[son][i-1]+2*M)%M;
for (int i=0; i<=k; i++) g[son][i]=(g[son][i]+g[node][i])%M;
for (int i=k; i>=1; i--) g[son][i]=(g[son][i]+g[son][i-1])%M;

Dfs2(son);
}
}

int main()
{
freopen("2159.in","r",stdin);
freopen("2159.out","w",stdout);

int L,now,A,B,Q,tmp;
scanf("%d%d%d",&n,&k,&L);
for (int i=1; i<=n; i++) head[i]=NULL;
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);
int x=i-now%tmp,y=i+1;
}

for (int i=1; i<=k; i++) S[i][1]=1;
for (int i=2; i<=k; i++)
for (int j=2; j<=i; j++)
S[i][j]=(S[i-1][j-1]+S[i-1][j]*j)%M;
fac[0]=1;
for (int i=1; i<=k; i++) fac[i]=fac[i-1]*i%M;
for (int i=1; i<=k; i++) h[i]=S[k][i]*fac[i]%M;

Dfs1(1);
Dfs2(1);

for (int i=1; i<=n; i++)
{
int ans=0;
for (int j=0; j<=k; j++) ans=(ans+ (f[i][j]+g[i][j])*h[j] )%M;
printf("%d\n",ans);
}

return 0;
}

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客