题解 Crash 的文明世界

题目传送门

题目大意

给出一个\(n\)个点的树,和常数\(k\),对于\(\forall i\in[1,n]\),求出:

\[\sum_{j=1}^{n} \text{dist}(i,j)^k \]

\(n\le 5\times 10^4,k\le 150\)

思路

真的很妙,一开始完全没有思路,看了\(\texttt{y2823774827y}\)的题解之后瞬间懂了。

我们考虑对于\(i\)如何计算答案,我们发现这个指数非常不好看,于是我们可以使用第二类斯特林数展开,就跟组合数问题差不多的,变为:

\[\sum_{j=1}^{n}\sum_{d=0}^{\text{dist}(i,j)}\binom{\text{dist}(i,j)}{d}\begin{Bmatrix}k\\d\end{Bmatrix}d! \]

交换求和顺序可以得到:

\[=\sum_{d=0}^{\min(n,k)}\begin{Bmatrix}k\\d\end{Bmatrix}d!\sum_{j=1}^{n}\binom{\text{dist}(i,j)}{d} \]

于是,我们的问题就是如何快速求出后面那个\(\sum\)。我们想到这个东西可以拆成:

\[\binom{\text{dist}(i,j)}{d}=\binom{\text{dist}(i,j)-1}{d}+\binom{\text{dist}(i,j)-1}{d-1} \]

于是,我们用换根\(dp\)解决这个问题了。具体见代码。

\(\texttt{Code}\)

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define MAXN 50005
#define mod 10007
#define MAXM 155

int qkpow (int a,int b){
	int res = 1;for (;b;b >>= 1,a = 1ll * a * a % mod) if (b & 1) res = 1ll * res * a % mod;
	return res;
}

int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}

struct edge{
	int v,nxt; 
}e[MAXN << 1];

int top = 1,head[MAXN];

void Add_Edge (int u,int v){
	e[++ top] = edge {v,head[u]},head[u] = top;
	e[++ top] = edge {u,head[v]},head[v] = top;
} 

int n,k,S[MAXM][MAXM],fac[MAXM],dp1[MAXN][MAXM],dp2[MAXN][MAXM],tmp[MAXM];
//dp1[u][k]表示的是\sum_{j在i的子树内(包括i)} \binom{dist(i,j)}{k} 
//dp2[u][k]表示的是\sum_{j=1}^{n} \binom{dist(i,j)}{k}

void dfs1 (int u,int fa){
	dp1[u][0] = 1;
	for (Int i = head[u];i;i = e[i].nxt){
		int v = e[i].v;
		if (v == fa) continue;
		dfs1 (v,u);
		for (Int j = 1;j <= k;++ j) dp1[u][j] = add (dp1[u][j],add (dp1[v][j],dp1[v][j - 1]));
		dp1[u][0] = add (dp1[u][0],dp1[v][0]);
	}
}

void dfs2 (int u,int fa){//换根dp 
	for (Int i = 0;i <= k;++ i) dp2[u][i] = dp1[u][i];
	if (fa){
		for (Int i = 1;i <= k;++ i) tmp[i] = dec (dp2[fa][i],add (dp1[u][i],dp1[u][i - 1]));
		tmp[0] = dec (dp2[fa][0],dp1[u][0]);
		for (Int i = 1;i <= k;++ i) dp2[u][i] = add (dp2[u][i],add (tmp[i],tmp[i - 1]));
		dp2[u][0] = add (dp2[u][0],tmp[0]);
	} 
	for (Int i = head[u];i;i = e[i].nxt){
		int v = e[i].v;
		if (v == fa) continue;
		dfs2 (v,u);
	}
}

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}

signed main(){
	read (n,k),S[0][0] = fac[0] = 1;
	for (Int i = 1;i <= k;fac[i] = mul (i,fac[i - 1]),++ i)
		for (Int j = 1;j <= i;++ j)
			S[i][j] = add (S[i - 1][j - 1],mul (j,S[i - 1][j]));
	for (Int i = 2,u,v;i <= n;++ i) read (u,v),Add_Edge (u,v);
	dfs1 (1,0),dfs2 (1,0);
	for (Int i = 1;i <= n;++ i){
		int sum = 0;
		for (Int j = 0;j <= k;++ j) sum = add (sum,mul (fac[j],mul (S[k][j],dp2[i][j])));
		write (sum),putchar ('\n');
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/Dark-Romance/p/13383677.html