题目描述

​ 给你一棵 n 个点的树,对于树上的每个节点 i,求 \(\sum_{j=1}^ndis(i,j)^k\)。其中 \(dis(i,j)\) 为两点在树上的距离。

输入格式

​ 第一行两个整数 n,k。

​ 接下来 n-1 行,每行两个整数 (x,y),表示一条树边。

输出格式

​ 一行一个整数,表示答案对 10007 取模的值。

样例输入

5 2
1 2
1 3
2 4
2 5

样例输出

10
7
23
18
18

数据范围

​ 对于 \(30\%\) 的数据,\(n\le5000,k\le50\)

​ 对于另 \(20\%\) 的数据,保证树是一条链

​ 对于所有数据,\(n\le50000,k\le150\)

解析

题目要求的值即为\(\sum_{i=1}^{n}dis(x,i)^k\)。形式上可以用第二类斯特林数的性质进行化简。

\[\begin{align}
Ans &= \sum_{i=1}^{n}dis(x,i)^k \\
&= \sum_{i=1}^{n} \sum_{j=0}^{k} S(k,j)*j!*C_{dis(x,i)}^{j}\\
&= \sum_{j=0}^{k}S(k,j)*j!*\sum_{i=1}^{n}(C_{dis(x,i)-1}^{j}+C_{dis(x,i)-1}^{j-1})\\
\end{align}
\]

其中斯特林数和阶乘都是可以预处理的。接下来的问题是如何求\(\sum_{i=1}^{n}C_{dis(x,i)}^{j}\)。

设\(f[i][j]\)表示对于第i个点的子树中上式的值,则\(C_{dis(x,i)-1}^{j}\)的值可以看做是在i点儿子的f中并由儿子推出\(f[i][j]\)的值。那么我们可以先假设1号点为根节点,用一遍dfs求出f的值,状态转移方程为

\[f[i][j]=\sum_{son}f[son][j]+f[son][j-1]
\]

然后用换根DP求出以任意i点作为根节点时的\(f[i][j]\)即可。最后的答案为

\[\sum_{j=0}^{k}S(k,j)*j!*f[i][j]
\]

动态规划时注意边界条件。

代码

#include <iostream>
#include <cstdio>
#define N 50002
#define K 201
#define int long long
using namespace std;
const int mod=10007;
int head[N],ver[N*2],nxt[N*2],l;
int n,k,i,j,f1[N][K],f2[N][K],g[K],f[K],s[K][K];
void insert(int x,int y)
{
l++;
ver[l]=y;
nxt[l]=head[x];
head[x]=l;
}
void dfs1(int x,int pre)
{
f1[x][0]=1;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y!=pre){
dfs1(y,x);
for(int j=1;j<=k;j++) f1[x][j]=(f1[x][j]+f1[y][j]+f1[y][j-1])%mod;
f1[x][0]=(f1[x][0]+f1[y][0])%mod;
}
}
}
void dfs2(int x,int pre)
{
for(int i=0;i<=k;i++) f2[x][i]=f1[x][i];
if(pre){
for(int i=1;i<=k;i++) g[i]=(f2[pre][i]-f1[x][i]+mod-f1[x][i-1]+mod)%mod;
g[0]=(f2[pre][0]-f1[x][0]+mod)%mod;
for(int i=1;i<=k;i++) f2[x][i]=(f2[x][i]+g[i]+g[i-1])%mod;
f2[x][0]=(f2[x][0]+g[0])%mod;
}
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y!=pre) dfs2(y,x);
}
}
signed main()
{
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
cin>>n>>k;
for(i=1;i<n;i++){
int u,v;
cin>>u>>v;
insert(u,v);
insert(v,u);
}
s[0][0]=s[1][1]=1;
f[0]=1;
for(i=1;i<=k;i++){
for(j=1;j<=k;j++) s[i][j]=(s[i-1][j-1]+j*s[i-1][j])%mod;
}
for(i=1;i<=k;i++) f[i]=f[i-1]*i%mod;
dfs1(1,0);
dfs2(1,0);
for(i=1;i<=n;i++){
int ans=0;
for(j=0;j<=k;j++) ans=(ans+(s[k][j]*f[j]%mod*f2[i][j])%mod)%mod;
cout<<ans<<endl;
}
fclose(stdin);
fclose(stdout);
return 0;
}

洛谷 P4827 [国家集训队] Crash 的文明世界的更多相关文章

  1. 洛谷P4827 [国家集训队] Crash 的文明世界 [斯特林数,组合数,DP]

    传送门 思路 又见到这个\(k\)次方啦!按照套路,我们将它搞成斯特林数: \[ ans_x=\sum_{i=0}^k i!S(k,i)\sum_y {dis(x,y) \choose i} \] 前 ...

  2. P4827 [国家集训队] Crash 的文明世界

    传送门:洛谷 题目大意:设$$S(i)=\sum_{j=1}^ndis(i,j)^k$$,求$S(1),S(2),\ldots,S(n)$. 数据范围:$n\leq 50000,k\leq 150$ ...

  3. P4827 [国家集训队] Crash 的文明世界(第二类斯特林数+树形dp)

    传送门 对于点\(u\),所求为\[\sum_{i=1}^ndis(i,u)^k\] 把后面那堆东西化成第二类斯特林数,有\[\sum_{i=1}^n\sum_{j=0}^kS(k,j)\times ...

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

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

  5. 洛谷 P1829 [国家集训队]Crash的数字表格 / JZPTAB 解题报告

    [国家集训队]Crash的数字表格 / JZPTAB 题意 求\(\sum\limits_{i=1}^n\sum\limits_{j=1}^mlcm(i,j)\),\(n,m\le 10^7\) 鉴于 ...

  6. 洛谷P1829 [国家集训队]Crash的数字表格

    题目描述 今天的数学课上,Crash小朋友学习了最小公倍数(Least Common Multiple).对于两个正整数a和b,LCM(a, b)表示能同时整除a和b的最小正整数.例如,LCM(6, ...

  7. 洛谷P1829 [国家集训队]Crash的数字表格 / JZPTAB(莫比乌斯反演)

    题目背景 提示:原 P1829 半数集问题 已经迁移至 P1028 数的计算 题目描述 今天的数学课上,Crash小朋友学习了最小公倍数(Least Common Multiple).对于两个正整数a ...

  8. 洛谷P1829 [国家集训队]Crash的数字表格 / JZPTAB(莫比乌斯反演)

    传送门 式子好麻烦orz……大佬好腻害orz->这里 //minamoto #include<iostream> #include<cstdio> #define ll ...

  9. 洛谷 P1829 [国家集训队]Crash的数字表格 / JZPTAB(莫比乌斯反演)

    题意:求$\sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j)$. 开始开心(自闭)化简: $\sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j)$ =$\su ...

随机推荐

  1. Linux内核调试方法总结之内核通知链

    Linux内核通知链notifier 1.内核通知链表简介(引用网络资料)    大多数内核子系统都是相互独立的,因此某个子系统可能对其它子系统产生的事件感兴趣.为了满足这个需求,也即是让某个子系统在 ...

  2. (转)VS2010结合水晶报表做条码标签打印功能

    本文转载自:http://blog.sina.com.cn/s/blog_552ca1400100y6dd.html 先来个功能效果图: 大家都知道VS2005和VS2008软件本身是包含水晶报表插件 ...

  3. 将String转化成Stream,将Stream转换成String, C# Stream 和 byte[] 之间的转换(文件流的应用)

    static void Main( string[] args ) { string str = "Testing 1-2-3"; //convert string 2 strea ...

  4. tar 打包文件

    tar支持通配符, 可以用* ?等来指定多个文件 在指明压缩文件名的时候, 一定要带上 -f选项 压缩文件名中间 最好不要带特殊符号, 如& ? * +等, shell bash 会作一些特殊 ...

  5. Docker - 部署 Ant Design Pro 的项目

    解读 Ant Design Pro 的 Docker 配置 package.json 的 scripts -f: 使用什么配置文件 -t: 标签 up: 启动服务(的容器) build: 构建或重新构 ...

  6. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_04 IO字节流_6_字节输出流写多个字节的方法

    一次写多个字节的方法 要在txt内显示100.49代表1 48 代表0 一次写多个字节 负数前两个组成一个中文.-65和-66 字节数组的一部分 写入字符串方法 当前用的编码格式是utf-8,utf- ...

  7. MySQL使用命令导出/导入数据

    导出数据库文件 常用命令 mysqldump -uroot -pMyPassword databaseName tableName1 tableName2 > /home/foo.sql mys ...

  8. vueStudy

    目录层次: 目前学习曲线有三个前端开发,每个人有各自的目录,可以很好地对比彼此的代码.  unit1 邮箱验证 用户名 数字.字母.中文 .划线不能以下划线开头 2-12位 密码验证 6-20位英文和 ...

  9. 《剑指offer》面试题15 链表中的倒数第k个节点 Java版

    书中方法:用两个节点一次遍历求得倒数第k个节点.注意头节点为空,k<=0,k大于节点个数的情况. public ListNode find(ListNode head, int k){ if(h ...

  10. [2019杭电多校第一场][hdu6579]Operation(线性基)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6579 题目大意是两个操作,1个是求[l,r]区间子序列的最大异或和,另一个是在最后面添加一个数. 如果 ...