Luogu4827 Crash的文明世界 组合树形DP
Posted itst
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu4827 Crash的文明世界 组合树形DP相关的知识,希望对你有一定的参考价值。
又是喜闻乐见的\(k\)次幂求和题目
那么\(S(x) = \sum\limits_{i=1}^n dist(i,x)^k = \sum\limits_{i=1}^n \sum\limits_{j=1}^k \binom{dist(i,x)}{j} \left\{ \begin{array}{cccc} k \\ j \end{array}\right\} j! = \sum\limits_{j=1}^k \left\{ \begin{array}{cccc} k \\ j \end{array}\right\} j! \sum\limits_{i=1}^n \binom{dist(i,x)}{j}\)。
因为组合数有优秀的性质:\(\binom{i+1}{j}=\binom{i}{j} + \binom{i}{j - 1}\),可以用这一个式子做一个DP。
设\(x\)和\(x\)的子树集合为\(S_x\),\(dp_{i,j}=\sum\limits_{x \in S_i}\binom{dist(i,x)}{j}\),转移的时候考虑\(i\)的孩子\(x\),\(dp_x\)中的所有\(dist\)都会加上\(1\),也就是说\(dp_{i,j} += \sum\limits_{y \in S_x} \binom{dist(x,y)+1}{j} = \sum\limits_{y \in S_x} (\binom{dist(x,y)}{j}+\binom{dist(x,y)}{j-1}) = dp_{x,j}+dp_{x,j-1}\),初始每一个节点\(i\)的\(dp_{i,0}=1\),其余为\(0\)。
接下来设\(up_{i,j} = \sum\limits_{x \not\in S_i}\binom{dist(i,x)}{j}\),转移从一个点\(i\)转移到它的孩子\(x\),将\(dp_x\)对\(dp_i\)的贡献消除之后得到\(dp'_i\),那么不难得到\(up_{x,j} = up_{i,j}+up_{i,j-1}+dp'_{i,j}+dp'_{i,j-1}\)。
最后\(\sum\limits_{i=1}^n \binom{dist(i,x)}{j} = dp_{x,j} + up_{x,j}\)。
#include<bits/stdc++.h>
//this code is written by Itst
using namespace std;
int read(){
int a = 0; char c = getchar();
while(!isdigit(c)) c = getchar();
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return a;
}
const int _ = 50003 , MOD = 10007;
struct Edge{
int end , upEd;
}Ed[_ << 1];
int dp[_][157] , up[_][157] , tmp[157] , S[157][157] , ans[_];
int N , K , head[_] , cntEd;
void addEd(int a , int b){
Ed[++cntEd] = (Edge){b , head[a]};
head[a] = cntEd;
}
void dfs1(int x , int p){//dp
dp[x][0] = 1;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(Ed[i].end != p){
dfs1(Ed[i].end , x);
for(int j = K ; j ; --j)
dp[x][j] = (dp[x][j] + dp[Ed[i].end][j] + dp[Ed[i].end][j - 1]) % MOD;
dp[x][0] = (dp[x][0] + dp[Ed[i].end][0]) % MOD;
}
}
void dfs2(int x , int p){//up
for(int i = 0 ; i <= K ; ++i)
tmp[i] = (up[x][i] + dp[x][i]) % MOD;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(Ed[i].end != p){
up[Ed[i].end][0] = (tmp[0] + MOD - dp[Ed[i].end][0]) % MOD;
for(int j = 1 ; j <= K ; ++j)
up[Ed[i].end][j] = (tmp[j] + 2 * MOD - (dp[Ed[i].end][j] + dp[Ed[i].end][j - 1])) % MOD;
for(int j = K ; j ; --j)
up[Ed[i].end][j] = (up[Ed[i].end][j] + up[Ed[i].end][j - 1]) % MOD;
}
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(Ed[i].end != p)
dfs2(Ed[i].end , x);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
N = read(); K = read();
for(int i = 1 ; i < N ; ++i){
int a = read() , b = read();
addEd(a , b); addEd(b , a);
}
S[1][1] = 1;
for(int i = 2 ; i <= K ; ++i)
for(int j = 1 ; j <= i ; ++j)
S[i][j] = (S[i - 1][j - 1] + S[i - 1][j] * j) % MOD;
dfs1(1 , 0); dfs2(1 , 0);
int fac = 1;
for(int j = 1 ; j <= K ; ++j){
fac = 1ll * fac * j % MOD;
for(int i = 1 ; i <= N ; ++i)
ans[i] = (ans[i] + 1ll * (dp[i][j] + up[i][j]) * fac * S[K][j]) % MOD;
}
for(int i = 1 ; i <= N ; ++i)
printf("%d\n" , ans[i]);
return 0;
}
以上是关于Luogu4827 Crash的文明世界 组合树形DP的主要内容,如果未能解决你的问题,请参考以下文章