题目简述:给定$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. 转载 ---资深HR告诉你:我如何筛选简历与选择人员的

    资深HR告诉你:我如何筛选简历与选择人员的   有个公司HR看简历 先直接丢掉一半 理由是不要运气不好的应聘者. 当然这可能只是某些HR面对太多的简历产生了偷懒的情绪,但是不论是Manager,亦或是 ...

  2. mongodb启动不了:提示错误信息为 child process failed, exited with error number 100

    [启动mongo 副本集错误提示]: [原因分析说明]: 查询很多资料得知由于上次使用了暴力关闭系统或者DB,导致数据文件锁住. [解决办法]: 1.  在 mongo.conf 文件添加一下属性值  ...

  3. inclusion_tag 看图

  4. Redis实现主从复制(转)

    一.Redis的Replication: 这里首先需要说明的是,在Redis中配置Master-Slave模式真是太简单了.相信在阅读完这篇Blog之后你也可以轻松做到.这里我们还是先列出一些理论性的 ...

  5. 【模板】P3806点分治1

    [模板]P3806 [模板]点分治1 很好的一道模板题,很无脑经典. 讲讲淀粉质吧,很营养,实际上,点分治是树上的分治算法.根据树的特性,树上两点的路径只有一下两种情况: 路径经过根\((*)\) 路 ...

  6. 题解 P4799 【[CEOI2015 Day2]世界冰球锦标赛】

    题解 P4799 [[CEOI2015 Day2]世界冰球锦标赛] 双向搜索好题 传送门 实际上,双向搜索就是把\(a^n\)的复杂度转变成了大多为\(O(nlogna^{\frac{n}{2}})\ ...

  7. AsyncHttpClien访问网络案例分析

    Android数据存储的四种方式分别是:SharedPreferences存储.File文件存储.Network网络存储和sqlite数据库存储,网络存储需要使用AsyncHttpClient发送请求 ...

  8. div中p标签自动换行

    只需要设置div的width属性,p标签加上word-break:break-word属性就会自动换行 ----------------2016.7.1-------------------- 今天在 ...

  9. P3746 [六省联考2017]组合数问题

    P3746 [六省联考2017]组合数问题 \(dp_{i,j}\)表示前\(i\)个物品,取的物品模\(k\)等于\(r\),则\(dp_{i,j}=dp_{i-1,(j-1+k)\%k}+dp_{ ...

  10. Android NDK环境搭建

    本文主要记录NDK环境在Ubuntu下的搭建. 下载NDK 在官网进行下载NDK https://developer.android.com/ndk/downloads/index.html 当前最新 ...