题目简述:给定$n \leq 50000$个节点的数,每条边的长度为$1$,对每个节点$u$,求

$$ E_u = \sum_{v=1}^n (d(u, v))^k, $$

其中$d(u, v)$是节点$u$和节点$v$的距离,而$k \leq 500$是一个常数。

解1:

斯特林数的性质,我们注意到

$$ x^n = \sum_{k=0}^n \begin{Bmatrix} n \\ k \end{Bmatrix} x^{\underline{k}}. $$

从而,

$$ E_u = \sum_{v=1}^n (d(u, v))^k = \sum_{i=0}^k \begin{Bmatrix} k \\ i \end{Bmatrix} \sum_{v=1}^n (d(u, v))^{\underline{i}}. $$

为此,我们定义

$$f[u][k] = \sum_{v \in T_u} (d(u, v))^{\underline{k}},$$

其中$T_u$表示以$u$为根节点的子树。令$\text{son}(u)$表示节点$u$的所有儿子节点的集合,并注意到$(x+1)^{\underline{k}} = x^{\underline{k}}+kx^{\underline{k-1}}$,则

$$
\begin{aligned}
f[u][k]
& = \sum_{v \in \text{son}(u)} \sum_{w \in T_v} (d(u, w))^{\underline{k}} \\
& = \sum_{v \in \text{son}(u)} \sum_{w \in T_v} (d(v, w)+1)^{\underline{k}} \\
& = \sum_{v \in \text{son}(u)} \sum_{w \in T_v} \Big( (d(v, w))^{\underline{k}}+k (d(v, w))^{\underline{k-1}} \Big) \\
& = \sum_{v \in \text{son}(u)} \Big( f[v][k]+k f[v][k-1] \Big)
\end{aligned}
$$

两遍DFS即可求出所有$E_u$,从而可在$O(nk)$的复杂度内解决。

 #include <bits/stdc++.h>

 using namespace std;

 typedef long long ll;
typedef unsigned long long ull;
typedef double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd; #define X first
#define Y second //#include <boost/unordered_map.hpp>
//using namespace boost; /*
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> rbtree;
rbtree T;
*/ namespace io{
const int L = ( << ) + ; char buf[L], *S , *T, c; char getchar() {
if(__builtin_expect(S == T, )) {
T = (S = buf) + fread(buf, , L, stdin);
return (S == T ? EOF : *S++);
}
return *S++;
} int inp() {
int x = , f = ; char ch;
for(ch = getchar(); !isdigit(ch); ch = getchar())
if(ch == '-') f = -;
for(; isdigit(ch); x = x * + ch - '', ch = getchar());
return x * f;
} unsigned inpu()
{
unsigned x = ; char ch;
for(ch = getchar(); !isdigit(ch); ch = getchar());
for(; isdigit(ch); x = x * + ch - '', ch = getchar());
return x;
} ll inp_ll() {
ll x = ; int f = ; char ch;
for(ch = getchar(); !isdigit(ch); ch = getchar())
if(ch == '-') f = -;
for(; isdigit(ch); x = x * + ch - '', ch = getchar());
return x * f;
} char B[], *outs=B+, *outr=B+;
template<class T>
inline void print(register T a,register char x=){
if(x) *--outs = x, x = ; if(!a)*--outs = '';
else
while(a)
*--outs = (a % ) + , a /= ; if(x)
*--outs = x; fwrite(outs, outr - outs , , stdout);
outs = outr;
}
}; using io :: print;
using io :: inp;
using io :: inpu;
using io :: inp_ll; using i32 = int;
using i64 = long long;
using u8 = unsigned char;
using u32 = unsigned;
using u64 = unsigned long long;
using f64 = double;
using f80 = long double; ll power(ll a, ll b, ll p)
{
if (!b) return ;
ll t = power(a, b/, p);
t = t*t%p;
if (b&) t = t*a%p;
return t;
} ll exgcd(ll a, ll b, ll &x, ll &y)
{
if (b == )
{
x = ;
y = ;
return a;
}
ll px, py;
ll d = exgcd(b, a%b, px, py);
x = py;
y = px-a/b*py;
return d;
} template<class T>
inline void freshmin(T &a, const T &b)
{
if (a > b) a = b;
} template<class T>
inline void freshmax(T &a, const T &b)
{
if (a < b) a = b;
} const int MAXN = ;
const int MAXK = ;
const int MOD = ;
const f80 MI = f80()/MOD;
const int INF = ; int n, k;
int S[MAXK][MAXK]; vector<int> v[MAXN];
int f[MAXN][MAXK], g[MAXN][MAXK]; void dfs1(int x, int p)
{
f[x][] = ;
for (int i = ; i <= k; ++ i)
f[x][i] = ;
for (auto y : v[x])
{
if (y == p) continue;
dfs1(y, x);
(f[x][] += f[y][]) %= MOD;
for (int i = ; i <= k; ++ i)
(f[x][i] += f[y][i]+i*f[y][i-]) %= MOD;
}
} void dfs2(int x, int p)
{
if (!p)
{
for (int i = ; i <= k; ++ i)
g[x][i] = f[x][i];
}
for (auto y : v[x])
{
if (y == p) continue;
g[y][] = g[x][];
for (int i = ; i <= k; ++ i)
{
int g1 = (g[x][i]-(f[y][i]+i*f[y][i-]))%MOD;
int g2 = (g[x][i-]-(f[y][i-]+(i-)*(i- >= ? f[y][i-] : )))%MOD;
g[y][i] = (f[y][i]+g1+i*g2)%MOD;
}
dfs2(y, x);
}
} int main()
{ S[][] = ;
for (int i = ; i <= ; ++ i)
for (int j = ; j <= i; ++ j)
S[i][j] = (S[i-][j-]+S[i-][j]*j)%MOD; for (int T = inp(); T --; )
{
n = inp();
k = inp();
for (int i = ; i <= n; ++ i)
v[i].clear();
for (int i = ; i < n; ++ i)
{
int x = inp();
int y = inp();
v[x].push_back(y);
v[y].push_back(x);
}
dfs1(, );
dfs2(, );
for (int x = ; x <= n; ++ x)
{
int ret = ;
for (int i = ; i <= k; ++ i)
(ret += S[k][i]*g[x][i]) %= MOD;
printf("%d\n", (ret+MOD)%MOD);
}
} return ;
}

解2:

我们用另一个斯特林数的性质:

$$ x^n = \sum_{k=0}^n k! \begin{Bmatrix} n \\ k \end{Bmatrix} \binom{x}{k}. $$

从而,

$$ E_u = \sum_{v=1}^n (d(u, v))^k = \sum_{i=0}^k i! \begin{Bmatrix} k \\ i \end{Bmatrix} \sum_{v=1}^n \binom{d(u, v)}{i}. $$

为此,我们定义

$$f[u][k] = \sum_{v \in T_u} \binom{d(u, v)}{k},$$

其中$T_u$表示以$u$为根节点的子树。令$\text{son}(u)$表示节点$u$的所有儿子节点的集合,则

$$
\begin{aligned}
f[u][k] 
& = \sum_{v \in \text{son}(u)} \sum_{w \in T_v} \binom{d(u, w)}{k} \\
& = \sum_{v \in \text{son}(u)} \sum_{w \in T_v} \binom{d(v, w)+1}{k} \\
& = \sum_{v \in \text{son}(u)} \sum_{w \in T_v} \left( \binom{d(v, w)}{k} + \binom{d(v, w)}{k-1} \right) \\
& = \sum_{v \in \text{son}(u)} \Big( f[v][k]+f[v][k-1] \Big)
\end{aligned}
$$

两遍DFS即可求出所有$E_u$,从而可在$O(nk)$的复杂度内解决。

 #include <bits/stdc++.h>

 using namespace std;

 typedef long long ll;
typedef unsigned long long ull;
typedef double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd; #define X first
#define Y second //#include <boost/unordered_map.hpp>
//using namespace boost; /*
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> rbtree;
rbtree T;
*/ namespace io{
const int L = ( << ) + ; char buf[L], *S , *T, c; char getchar() {
if(__builtin_expect(S == T, )) {
T = (S = buf) + fread(buf, , L, stdin);
return (S == T ? EOF : *S++);
}
return *S++;
} int inp() {
int x = , f = ; char ch;
for(ch = getchar(); !isdigit(ch); ch = getchar())
if(ch == '-') f = -;
for(; isdigit(ch); x = x * + ch - '', ch = getchar());
return x * f;
} unsigned inpu()
{
unsigned x = ; char ch;
for(ch = getchar(); !isdigit(ch); ch = getchar());
for(; isdigit(ch); x = x * + ch - '', ch = getchar());
return x;
} ll inp_ll() {
ll x = ; int f = ; char ch;
for(ch = getchar(); !isdigit(ch); ch = getchar())
if(ch == '-') f = -;
for(; isdigit(ch); x = x * + ch - '', ch = getchar());
return x * f;
} char B[], *outs=B+, *outr=B+;
template<class T>
inline void print(register T a,register char x=){
if(x) *--outs = x, x = ; if(!a)*--outs = '';
else
while(a)
*--outs = (a % ) + , a /= ; if(x)
*--outs = x; fwrite(outs, outr - outs , , stdout);
outs = outr;
}
}; using io :: print;
using io :: inp;
using io :: inpu;
using io :: inp_ll; using i32 = int;
using i64 = long long;
using u8 = unsigned char;
using u32 = unsigned;
using u64 = unsigned long long;
using f64 = double;
using f80 = long double; ll power(ll a, ll b, ll p)
{
if (!b) return ;
ll t = power(a, b/, p);
t = t*t%p;
if (b&) t = t*a%p;
return t;
} ll exgcd(ll a, ll b, ll &x, ll &y)
{
if (b == )
{
x = ;
y = ;
return a;
}
ll px, py;
ll d = exgcd(b, a%b, px, py);
x = py;
y = px-a/b*py;
return d;
} template<class T>
inline void freshmin(T &a, const T &b)
{
if (a > b) a = b;
} template<class T>
inline void freshmax(T &a, const T &b)
{
if (a < b) a = b;
} const int MAXN = ;
const int MAXK = ;
const int MOD = ;
const f80 MI = f80()/MOD;
const int INF = ; int n, k;
int S[MAXK][MAXK]; vector<int> v[MAXN];
int f[MAXN][MAXK], g[MAXN][MAXK]; void dfs1(int x, int p)
{
f[x][] = ;
for (int i = ; i <= k; ++ i)
f[x][i] = ;
for (auto y : v[x])
{
if (y == p) continue;
dfs1(y, x);
(f[x][] += f[y][]) %= MOD;
for (int i = ; i <= k; ++ i)
(f[x][i] += f[y][i]+f[y][i-]) %= MOD;
}
} void dfs2(int x, int p)
{
if (!p)
{
for (int i = ; i <= k; ++ i)
g[x][i] = f[x][i];
}
for (auto y : v[x])
{
if (y == p) continue;
g[y][] = g[x][];
for (int i = ; i <= k; ++ i)
{
int g1 = (g[x][i]-(f[y][i]+f[y][i-]))%MOD;
int g2 = (g[x][i-]-(f[y][i-]+(i- >= ? f[y][i-] : )))%MOD;
g[y][i] = (f[y][i]+g1+g2)%MOD;
}
dfs2(y, x);
}
} int main()
{ S[][] = ;
for (int i = ; i <= ; ++ i)
for (int j = ; j <= i; ++ j)
S[i][j] = (S[i-][j-]+S[i-][j]*j)%MOD; for (int T = inp(); T --; )
{
n = inp();
k = inp();
for (int i = ; i <= n; ++ i)
v[i].clear();
for (int i = ; i < n; ++ i)
{
int x = inp();
int y = inp();
v[x].push_back(y);
v[y].push_back(x);
}
dfs1(, );
dfs2(, );
for (int x = ; x <= n; ++ x)
{
int ret = ;
int fact = ;
for (int i = ; i <= k; ++ i)
{
(ret += S[k][i]*fact%MOD*g[x][i]) %= MOD;
(fact *= i+) %= MOD;
}
printf("%d\n", (ret+MOD)%MOD);
}
} return ;
}

HDU 4625. JZPTREE的更多相关文章

  1. bzoj 2159 Crash 的文明世界 && hdu 4625 JZPTREE ——第二类斯特林数+树形DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2159 学习材料:https://blog.csdn.net/litble/article/d ...

  2. bzoj 2159 Crash 的文明世界 & hdu 4625 JZPTREE —— 第二类斯特林数+树形DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2159 使用公式:\( n^{k} = \sum\limits_{i=0}^{k} S(k,i ...

  3. HDU - 4625 JZPTREE(第二类斯特林数+树DP)

    https://vjudge.net/problem/HDU-4625 题意 给出一颗树,边权为1,对于每个结点u,求sigma(dist(u,v)^k). 分析 贴个官方题解 n^k并不好转移,于是 ...

  4. hdu 4625 Dice(概率DP)

    Dice Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submi ...

  5. 学习总结:斯特林数( Stirling number )

    基本定义 第一类斯特林数:$1 \dots n$的排列中恰好有$k$个环的个数:或是,$n$元置换可分解为$k$个独立的轮换的个数.记作 $$ \begin{bmatrix} n \\ k \end{ ...

  6. Solution Set - Stirling 数相关杂题

      <好多题的题解>   「洛谷 P5408」第一类斯特林数·行   根据结论 \[x^{\overline{n}}=\sum_i{n\brack i}x^i, \] 我们只需要求出 \( ...

  7. HDOJ 2111. Saving HDU 贪心 结构体排序

    Saving HDU Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  8. 【HDU 3037】Saving Beans Lucas定理模板

    http://acm.hdu.edu.cn/showproblem.php?pid=3037 Lucas定理模板. 现在才写,noip滚粗前兆QAQ #include<cstdio> #i ...

  9. hdu 4859 海岸线 Bestcoder Round 1

    http://acm.hdu.edu.cn/showproblem.php?pid=4859 题目大意: 在一个矩形周围都是海,这个矩形中有陆地,深海和浅海.浅海是可以填成陆地的. 求最多有多少条方格 ...

随机推荐

  1. python 基础 4.0 函数的一般形式及传参

    #/usr/bin/python #coding=utf-8 #@Time   :2017/10/23 15:58 #@Auther :liuzhenchuan #@File   :函数的一般形式.p ...

  2. Linuxt图形界面安装

    通常安装图形界面需要安装Xorg.桌面环境(Gnome.KDE.xfce等).字体等.你的Linux是什么版本?具体要看你的linux来决定用什么命令来安装. #yum grouplist 自己看看列 ...

  3. 一些重要的地址:md5在线解密破解

    md5在线解密破解:https://www.cmd5.com/

  4. centos 安装postgresql 完整版

    按步骤 执行命令即可: yum install https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/pgdg-c ...

  5. 【C语言天天练(十)】结构体

    引言:数据常常以成组的形式存在.在C中,使用结构能够把不同类型的值存放在一起. 结构的声明有两种 1.struct SIMPLE{ int a; char b; float c; };然后用标签SIM ...

  6. Swift语言概览

                     Swift语言概览 关于 这篇文章简要介绍了苹果于WWDC 2014公布的编程语言--Swift. 前言 在这里我觉得有必要提一下Brec Victor的Invent ...

  7. MySQL——事务

    核心知识: 1.什么是事务?一组原子性的SQL查询语句 2.事务的四种属性:ACID 3.四种隔离级别:读取未提交内容.读取提交内容.重复读.串行化. 4.什么是幻读?幻读有那些解决办法?连续读取同一 ...

  8. Java for LeetCode 084 Largest Rectangle in Histogram【HARD】

    For example, Given height = [2,1,5,6,2,3], return 10. 解题思路: 参考Problem H: Largest Rectangle in a Hist ...

  9. linux下 python源码包解压报错

    执行下面的命令 tar -zvxf Python.3.6.5.tgz 报错 gzip: stdin: not in gzip format tar: Child returned status 1 t ...

  10. 微信小程序开发:学习笔记[4]——样式布局

    微信小程序开发:学习笔记[4]——样式布局 Flex布局 新的布局方式 在小程序开发中,我们需要考虑各种尺寸终端设备上的适配.在传统网页开发,我们用的是盒模型,通过display:inline | b ...