题目传送门

题目大意

给出一个\(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;
}

题解 Crash 的文明世界的更多相关文章

  1. 【BZOJ2159】Crash的文明世界(第二类斯特林数,动态规划)

    [BZOJ2159]Crash的文明世界(第二类斯特林数,动态规划) 题面 BZOJ 洛谷 题解 看到\(k\)次方的式子就可以往二项式的展开上面考,但是显然这样子的复杂度会有一个\(O(k^2)\) ...

  2. P4827「国家集训队」 Crash 的文明世界

    「国家集训队」 Crash 的文明世界 提供一种不需要脑子的方法. 其实是看洛谷讨论版看出来的( (但是全网也就这一篇这个方法的题解了) 首先这是一个关于树上路径的问题,我们可以无脑上点分治. 考虑当 ...

  3. 【BZOJ2159】Crash的文明世界

    [2011集训贾志鹏]Crash的文明世界 Description Crash小朋友最近迷上了一款游戏--文明5(Civilization V).在这个游戏中,玩家可以建立和发展自己的国家,通过外交和 ...

  4. [国家集训队] Crash 的文明世界(第二类斯特林数)

    题目 [国家集训队] Crash 的文明世界 前置 斯特林数\(\Longrightarrow\)斯特林数及反演总结 做法 \[\begin{aligned} ans_x&=\sum\limi ...

  5. 题解 [BZOJ2159] Crash的文明世界

    题面 解析 这题一眼换根DP啊 首先,我们考虑一下如何转换\(n^m\)这个式子, 先把式子摆出来吧:\(n^m=\sum_{j=0}^mS(m,j)C_n^jj!\) 其中\(S(m,j)\)表示第 ...

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

    传送门 这个题......我谔谔 首先可以考虑换根\(dp\),但到后来发现二项式定理展开过后需要维护\(k\)个值,同时每个值也要\(O(k)\)的时间按二项式定理算 当然fft优化过后就是k lo ...

  7. 【bzoj 2159】Crash 的文明世界

    Description Crash小朋友最近迷上了一款游戏——文明5(Civilization V).在这个游戏中,玩家可以建立和发展自己的国家,通过外交和别的国家交流,或是通过战争征服别的国家.现在 ...

  8. bzoj 2159: Crash 的文明世界

    Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 480  Solved: 234[Submit][Status][Discuss] Descripti ...

  9. 【BZOJ2159】Crash的文明世界 斯特林数+树形dp

    Description Crash 小朋友最近迷上了一款游戏--文明5(Civilization V).在这个游戏中,玩家可以建立和发展自己的国家,通过外交和别的国家交流,或是通过战争征服别的国家.现 ...

随机推荐

  1. rabbitMq内存与磁盘分配问题

    在服务器上也可以改变配置文件修改内存 也可以使用命令进行分配: 相对内存:rabbitmqctl  set_vm_memory_hgih_waterwmark 0.4     使用时可以把这个0.4替 ...

  2. Ansible部署及配置介绍

    原文转自:https://www.cnblogs.com/itzgr/p/10233932.html作者:木二 目录 一 Ansible的安装部署 1.1 PIP方式 1.2 YUM方式 二 Ansi ...

  3. openresty(nginx) 配置 http与https使用同一个端口,禁止 IP 直接访问

    准备好工作目录 mkdir work cd work mkdir conf logs 准备好 conf/nginx.conf 配置文件, 把 your.domain 换成你自己的域名 user abc ...

  4. mysqli的基本使用

    简单实例 面向过程方式 // 创建数据库连接 $connect = mysqli_connect('127.0.0.1', 'root', 'root', 'test', 8889); // 判读是否 ...

  5. Vs code自动生成Doxygen格式注释

    前言 ​ 程序中注释的规范和统一性的重要性不言而喻,本文就推荐一种在用vscode编写代码时自动化生成标准化注释格式的方法,关于Doxygen规范及其使用可查看博文 代码注释规范之Doxygen. ​ ...

  6. Linux 网卡驱动sk_buff内核源码随笔

    这几天在调试有关网卡驱动的东西,有很多地方不清楚.有关网卡驱动部分主要有两个很重要的结构体:struct net_device 和struct sk_buff. 驱动大部分都是围绕这两个东西进行操作的 ...

  7. Java 扫描识别条形码图片

    1.条形码扫描识别的实现方法及步骤 本文以Java代码示例介绍如何来扫描和识别条形码图片.这里使用免费条码工具 Free Spire.Barcode for Java,调用BarcodeScanner ...

  8. crontab 语法和最快速的学习

    1.Cron 时间表语法 # ┌───────────── 分钟 (0 - 59) # │ ┌───────────── 小时 (0 - 23) # │ │ ┌───────────── 月的某天 ( ...

  9. 【原创】【长期更新】【未完待续】自制vector类型

    继<自制string类型>以来的第二篇自制类型的文章.马上要开学了,时间也不多了,争取在今年写完吧. 目录 一,vector类型简单介绍 1.简介 1.1.STL 1.2.vector 2 ...

  10. php 开启报错

    // 开启报错提醒ini_set("display_errors", "On");error_reporting(E_ALL | E_STRICT); // 某 ...