题目简述:给定$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. 数据结构与算法之枚举(穷举)法 C++实现

    枚举法的本质就是从全部候选答案中去搜索正确的解,使用该算法须要满足两个条件: 1.能够先确定候选答案的数量. 2.候选答案的范围在求解之前必须是一个确定的集合. 枚举是最简单.最基础.也是最没效率的算 ...

  2. T-SQL高级查询语句(父子查询)

    T-SQL高级查询语句 高级查询 1.连接查询,对结果集列的扩展 select * from info select * from info,nation #形成笛卡尔积 select * from ...

  3. LoadRunner性能测试过程/流程

    用LoadRunner进行负载测试的流程通常由五个阶段组成:计划.脚本创建.场景定义.场景执行和结果分析.(1)计划负载测试:定义性能测试要求,例如并发用户的数量.典型业务流程和所需响应时间.(2)创 ...

  4. EasyNVR H5直播流媒体解决方案前端构建之:如何播放自动适配RTMP/HLS直播播放

    之前在进行EasyNVR多屏开发的时候,由于多屏功能不需要在手机端展示出来(pc多播放为RTMP,手机端播放为HLS),因此只注意到了引用videojs来进行rtmp的播放.由于不同项目需求不同,对h ...

  5. python之异步IO

    协程的用武之地 并发量较大的系统和容易在IO方面出现瓶颈(磁盘IO,网络IO),采用多线程.多进程可以解决这个问题,当然线程.进程的切换时很消耗资源的.最好的解决方案是使用单线程方式解决并发IO问题- ...

  6. (1)Web 应用是一个状态机,视图与状态是一一对应的。 (2)所有的状态,保存在一个对象里面。

    Redux 入门教程(一):基本用法 - 阮一峰的网络日志 http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_u ...

  7. 百度小程序转换微信小程序

    Python脚本,一键转换Github地址:https://github.com/DWmelon/py-transfer-BdToWx 运行条件 具备Python环境,可在命令行中使用Python命令 ...

  8. Java for LeetCode 123 Best Time to Buy and Sell Stock III【HARD】

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  9. c#使用itextsharp输出pdf(动态填充表单内容,显示中文)

    相关链接: iText的简单应用-字体 c#程序为PDF文件填写表单内容 示例代码: static void Main(string[] args) { BaseFont font = BaseFon ...

  10. 分享知识-快乐自己:Oracle SQL语法汇总

    --删除重复值-保留重复值最大的编号 delete from emp where rowid in( select rowid from emp where rowid not in( select ...