[国家集训队]Crash的文明世界 题解

8 篇文章 0 订阅

传送门

题意

给一棵树,设 S ( x ) = ∑ i = 1 n d i s t ( x , i ) k S(x)=\sum\limits_{i=1}^n\mathrm{dist}(x,i)^k S(x)=i=1ndist(x,i)k,对每个点求出 S ( x ) S(x) S(x)

n ≤ 5 × 1 0 4 , k ≤ 150 n\leq 5\times10^4,k\leq150 n5×104,k150

题解

不会点分树

首先我们知道第二类斯特林数 S i j S_i^j Sij满足这样一个关系

m n = ∑ i = 0 n S n i i ! C m i m^n=\sum\limits_{i=0}^nS_n^ii!C_m^i mn=i=0nSnii!Cmi

套进去

S ( x ) = ∑ i = 1 n ∑ j = 0 k S k j j ! C d i s t ( i , x ) j S(x)=\sum\limits_{i=1}^n\sum\limits_{j=0}^kS_k^jj!C_{\mathrm{dist}(i,x)}^j S(x)=i=1nj=0kSkjj!Cdist(i,x)j

交换求和符号

S ( x ) = ∑ j = 0 k S k j j ! ∑ i = 1 n C d i s t ( i , x ) j S(x)=\sum\limits_{j=0}^kS_k^jj!\sum\limits_{i=1}^nC_{\mathrm{dist}(i,x)}^j S(x)=j=0kSkjj!i=1nCdist(i,x)j
于是我们只要求后面那个 ∑ i = 1 n C d i s t ( i , x ) j \sum\limits_{i=1}^nC_{\mathrm{dist}(i,x)}^j i=1nCdist(i,x)j即可。

树形dp,设 f ( x , j ) = ∑ u ∈ X C d i s t ( x , u ) j f(x,j)=\sum\limits_{u\in X}C_{\mathrm{dist}(x,u)}^j f(x,j)=uXCdist(x,u)j,其中 X X X表示以 x x x为根的子树(包括 x x x本身)。
f ( x , j ) = ∑ u ∈ X ( C d i s t ( x , u ) − 1 j + C d i s t ( x , u ) − 1 j − 1 ) f(x,j)=\sum\limits_{u\in X}(C_{\mathrm{dist}(x,u)-1}^j+C_{\mathrm{dist}(x,u)-1}^{j-1}) f(x,j)=uX(Cdist(x,u)1j+Cdist(x,u)1j1)

u u u x x x的距离为 d i s t ( x , u ) \mathrm{dist}(x,u) dist(x,u) u u u又是 X X X中的点,那么与 u u u相距 d i s t ( x , u ) − 1 \mathrm{dist}(x,u)-1 dist(x,u)1的点也就是 x x x的孩子了。所以我们有转移

f ( x , j ) = ∑ v ∈ s o n ( x ) f ( v , j ) + f ( v , j − 1 ) f(x,j)=\sum\limits_{v\in \mathrm{son}(x)}f(v,j)+f(v,j-1) f(x,j)=vson(x)f(v,j)+f(v,j1)

其中 s o n ( x ) \mathrm{son}(x) son(x) x x x的孩子集合。

这样还不够,我们还需要求 g ( x , j ) = ∑ u ∉ X C d i s t ( x , u ) j g(x,j)=\sum\limits_{u\notin X}C_{\mathrm{dist}(x,u)}^j g(x,j)=u/XCdist(x,u)j

g ( x , j ) = ∑ u ∉ X ( C d i s t ( x , u ) − 1 j + C d i s t ( x , u ) − 1 j − 1 ) g(x,j)=\sum\limits_{u\notin X}(C_{\mathrm{dist}(x,u)-1}^j+C_{\mathrm{dist}(x,u)-1}^{j-1}) g(x,j)=u/X(Cdist(x,u)1j+Cdist(x,u)1j1)

= ∑ u ∉ X ( C d i s t ( f a ( x ) , u ) j + C d i s t ( f a ( x ) , u ) j − 1 ) =\sum\limits_{u\notin X}(C_{\mathrm{dist}(\mathrm{fa}(x),u)}^j+C_{\mathrm{dist}(\mathrm{fa}(x),u)}^{j-1}) =u/X(Cdist(fa(x),u)j+Cdist(fa(x),u)j1)
其中
∑ u ∉ X C d i s t ( f a ( x ) , u ) j = f ( f a ( x ) , j ) + g ( f a ( x ) , j ) − f ( x , j ) − f ( x , j − 1 ) \sum\limits_{u\notin X}C_{\mathrm{dist}(\mathrm{fa}(x),u)}^j=f(\mathrm{fa}(x),j)+g(\mathrm{fa}(x),j)-f(x,j)-f(x,j-1) u/XCdist(fa(x),u)j=f(fa(x),j)+g(fa(x),j)f(x,j)f(x,j1)
∑ u ∉ X C d i s t ( f a ( x ) , u ) j − 1 = f ( f a ( x ) , j − 1 ) + g ( f a ( x ) , j − 1 ) − f ( x , j − 1 ) − f ( x , j − 2 ) \sum\limits_{u\notin X}C_{\mathrm{dist}(\mathrm{fa}(x),u)}^{j-1}=f(\mathrm{fa}(x),j-1)+g(\mathrm{fa}(x),j-1)-f(x,j-1)-f(x,j-2) u/XCdist(fa(x),u)j1=f(fa(x),j1)+g(fa(x),j1)f(x,j1)f(x,j2)
做完了。

至于斯特林数怎么求,由于这里只要 k × k k\times k k×k范围内的,所以直接利用递推关系

S i j = S i − 1 j − 1 + j S i − 1 j S_i^j=S_{i-1}^{j-1}+jS_{i-1}^j Sij=Si1j1+jSi1j

就行了,不需要NTT之类的复杂玩意。

#include <cctype>
#include <cstdio>
#include <climits>
#include <algorithm>
#include <vector>

template <typename T> inline void read(T& x) {
    int f = 0, c = getchar(); x = 0;
    while (!isdigit(c)) f |= c == '-', c = getchar();
    while (isdigit(c)) x = x * 10 + c - 48, c = getchar();
    if (f) x = -x;
}
template <typename T, typename... Args>
inline void read(T& x, Args&... args) {
    read(x); read(args...); 
}
template <typename T> void write(T x) {
    if (x < 0) x = -x, putchar('-');
    if (x > 9) write(x / 10);
    putchar(x % 10 + 48);
}
template <typename T> inline void writeln(T x) { write(x); puts(""); }
template <typename T> inline bool chkmin(T& x, const T& y) { return y < x ? (x = y, true) : false; }
template <typename T> inline bool chkmax(T& x, const T& y) { return x < y ? (x = y, true) : false; }

const int mod = 10007;
const int maxn = 5e4 + 7, maxk = 157;

int stir[maxk][maxk], f[maxn][maxk], g[maxn][maxk], fac[maxk];
std::vector<int> G[maxn];
int n, K;

void dfs1(int x, int fa) {
    f[x][0] = 1;
    for (auto v : G[x]) if (v != fa) {
        dfs1(v, x);
        f[x][0] = (f[x][0] + f[v][0]) % mod;
        for (int j = 1; j <= K; ++j)
            f[x][j] = (f[x][j] + f[v][j] + f[v][j - 1]) % mod;
    }
}
void dfs2(int x, int fa) {
    if (x > 1) {
        g[x][0] = n - f[x][0];
        g[x][1] = ((f[fa][1] + g[fa][1] + f[fa][0] + g[fa][0] - f[x][1] - 2 * f[x][0]) % mod + mod) % mod;
        for (int j = 2; j <= K; ++j)
            g[x][j] = ((f[fa][j] + g[fa][j] + f[fa][j - 1] + g[fa][j - 1] - f[x][j] - 2 * f[x][j - 1] - f[x][j - 2]) % mod + mod) % mod;
    }
    for (auto v : G[x]) if (v != fa) dfs2(v, x);
}

int main() {
    read(n, K);
    for (int i = 1, x, y; i < n; ++i) {
        read(x, y);
        G[x].push_back(y);
        G[y].push_back(x);
    }
    stir[0][0] = 0; stir[1][1] = 1;
    for (int i = 2; i <= K; ++i)
        for (int j = 1; j <= i; ++j)
            stir[i][j] = (stir[i - 1][j - 1] + j * stir[i - 1][j] % mod) % mod;
    fac[0] = 1;
    for (int i = 1; i <= K; ++i) fac[i] = fac[i - 1] * i % mod;
    dfs1(1, 0);
    dfs2(1, 0);
    for (int i = 1; i <= n; ++i) {
        int si = 0;
        for (int j = 0; j <= K; ++j)
            si = (si + stir[K][j] * fac[j] % mod * (f[i][j] + g[i][j]) % mod) % mod;
        writeln(si);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值