题目链接

一道好题。

题意:给定一棵\(n\)个点的树,求:

\[\sum_{S\subseteq \{1,2,\dots,n\}}f(S)^k
\]

其中\(f(S)\)代表用树边将点集\(S\)连通需要的最少边数。\(n\leq10^5\),\(k\leq 200\),对\(10^9+7\)取模。

吐槽:比赛的时候看到这道题想到的是组合数做法,然而是\(O(nk^2)\)的,但可以用任意模数\(\text{NTT}\)优化到\(O(nk\log k)\),当然由于常数巨大结果可想而知。可以说是第一次感受到被1e9+7支配的恐惧。我觉得出题人模数不出\(998244353\)就是为了卡这种做法...当然正解的做法还是让人心服口服并且受益良多的。

题解:首先有一种套路叫做幂转下降幂,即这个等式:

\[x^k=\sum_{i=0}^k \begin{Bmatrix} k \\ i \end{Bmatrix}x^{\underline i}
\]

考虑它的一个等价形式:

\[x^k=\sum_{i=0}^k \begin{Bmatrix} k \\ i \end{Bmatrix}i!{x\choose i}
\]

应用到这道题的式子中,我们要求的就是:

\[\sum_{S\subseteq \{1,2,\dots,n\}}\sum_{i=0}^k \begin{Bmatrix} k \\ i \end{Bmatrix}i!{f(S)\choose i}
\]

考虑交换求和的顺序:

\[\sum_{i=0}^k \begin{Bmatrix} k \\ i \end{Bmatrix}i!\Bigg(\sum_{S\subseteq \{1,2,\dots,n\}}{f(S)\choose i}\Bigg)
\]

为了方便起见,我们在下文不严谨的称连通一个点集\(S\)的最小边集叫做点集\(S\)的虚树。

从组合意义上来讲,后面的式子等价于枚举所有大小为\(i\)的边集,计算虚树包含这个边集的点集数目并相加得到的结果。根据这一点,我们可以进行dp。我们设答案数组\(g_i=\sum_{S\subseteq \{1,2,\dots,n\}}{f(S)\choose i}\),那么只要知道\(g\)就很容易知道答案。

先考虑如何简化判断虚树的边的过程。首先,假如点集中所有点的\(lca\)就是根,那么存在一种非常简单的方法:对于每一个非根节点,假如点集至少包含一个它的子树中的点,那么它向父亲的边就会被包含。于是我们可以考虑枚举点集中所有点的\(lca\),设为\(x\),对于是\(x\)的子树的子集的所有非空点集,用上述方法来判断边数,我们不妨称这样得到的虚树为关于\(x\)的伪虚树。当然会有一部分不合法的,即所有点都在以\(x\)的某个儿子\(y\)的子树内,我们将关于\(x\)的伪虚树的贡献去掉即可。

我们设\(f_{x,i}\)表示所有大小为\(i\)的边集被多少个关于\(x\)的伪虚树包含。

为了方便,我们不妨在开始时将空集也计算在内,最后在去掉空集的影响,容易得知去掉空集只要在最后将\(f_{x,0}\)减\(1\)即可。

那么初始时只有\(x\)本身,考虑是否选择\(x\),两种情况都只有\(0\)条边,因此可以设\(f_{x,0}=2\)。

接下来考虑在原来的基础上如何添加一棵以\(y\)为根的子树。我们先考虑如何将关于\(y\)的伪虚树改造成关于\(x\)的伪虚树。我们设辅助数组\(tmp\),\(tmp_i\)表示所有大小为\(i\)的边集被多少个关于\(x\)的伪虚树中只含以\(y\)为根的子树中的点的伪虚树包含。如果是非空的子集,那么实际上就是多包含了\(y\)和\(x\)之间的边。于是我们根据边集是否包含新的这条边,得出转移\(tmp_i+=f_{y,i}+f_{y,i-1}\)。最后考虑空集的情况,那么\(tmp_0++\)。可以发现这里计算的伪虚树除空集以外都是不合法的,于是令\(g_i-=tmp_i\),最后加上额外减去的空集,即\(g_0++\)。

接下来只要根据乘法原理将\(f_x\)与\(tmp\)合并就可以得到新的\(f'_x\),转移方程为:

\[f'_{x,i}=\sum_{j=0}^if_{x,j}*tmp_{i-j}
\]

在算完所有子树以后就得到了所有关于\(x\)的伪虚树的贡献,我们先去掉空集,即\(f_{x,0}--\),再将贡献加入到答案数组中,即\(g_i+=f_{x,i}\)。

这样做的复杂度看上去是\(O(nk^2)\)的,但是考虑到合并\(x\)和\(y\)时,设\(size_x\)表示当前处理好的\(x\)的子树的点数,那么合并的代价实际上是\(\min(k,size_x)*\min(k,size_y)\)。

首先考虑若干个\(<k\)的子树进行合并直到合并为一个\(\geq k\)的子树,代价是\(O(k^2)\)的,最多合并成\(\frac{n}{k}\)个这样的,于是复杂度是\(O(nk)\)。

再考虑\(<k\)的与\(\geq k\)的合并,复杂度是\(O(size*k)\)的,那么由于每一点最多经历一次这个过程,复杂度也是\(O(nk)\)。

最后是两个\(\geq k\)的子树合并,由于只有最多\(\frac{n}{k}\)个这样的子树因此操作次数不超过\(\frac{n}{k}\),因此复杂度是\(O(nk)\)。

于是最终的复杂度是\(O(nk)\),降低复杂度的关键是合并的代价可以和子树大小取\(\min\)。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using std::min;
using std::vector;
const int mod=1e9+7;
inline int add(int a,int b)
{
return (a+=b)>=mod?a-mod:a;
}
inline int sub(int a,int b)
{
return (a-=b)<0?a+mod:a;
}
inline int mul(int a,int b)
{
return (long long)a*b%mod;
}
inline int qpow(int a,int b)
{
int res=1;
for(;b;a=mul(a,a),b>>=1)
if(b&1)
res=mul(res,a);
return res;
}
const int N=1e5+5,K=205;
int n,k,ans;
int S[K][K],fact[K];
int size[N];
vector<int> e[N];
int f[N][K];
int tmp[K],tmp2[K];
int g[K];
void dfs(int x,int father)
{
int kx,ky;
register int i,j;
f[x][0]=2;size[x]=1;
for(auto y:e[x])
if(y!=father)
{
dfs(y,x);kx=min(k,size[x]);ky=min(k,size[y]);
memcpy(tmp,f[y],sizeof(int)*(ky+1));
for(i=ky;i>0;i--)
tmp[i]=add(tmp[i],tmp[i-1]);
for(i=0;i<=ky;i++)
g[i]=sub(g[i],tmp[i]);
tmp[0]=add(tmp[0],1);
memset(tmp2,0,sizeof(int)*(k+1));
for(i=0;i<=kx;i++)
for(j=0;j<=ky&&i+j<=k;j++)
tmp2[i+j]=add(tmp2[i+j],mul(f[x][i],tmp[j]));
memcpy(f[x],tmp2,sizeof(int)*(k+1));
size[x]+=size[y];
}
f[x][0]=sub(f[x][0],1);
kx=min(k,size[x]);
for(i=0;i<=kx;i++)
g[i]=add(g[i],f[x][i]);
return;
}
signed main()
{
int x,y;
register int i,j;
scanf("%d%d",&n,&k);
fact[0]=1;
for(i=1;i<=k;i++)
fact[i]=mul(fact[i-1],i);
S[0][0]=1;
for(i=1;i<=k;i++)
{
S[i][0]=0;S[i][i]=1;
for(j=1;j<i;j++)
S[i][j]=add(S[i-1][j-1],mul(j,S[i-1][j]));
}
for(i=1;i<=n-1;i++)
{
scanf("%d%d",&x,&y);
e[x].push_back(y);
e[y].push_back(x);
}
dfs(1,0);
for(i=1;i<=k;i++)
ans=add(ans,mul(mul(S[k][i],fact[i]),g[i]));
printf("%d\n",ans);
return 0;
}

Codeforces 1097 G. Vladislav and a Great Legend的更多相关文章

  1. [codeforces 549]G. Happy Line

    [codeforces 549]G. Happy Line 试题描述 Do you like summer? Residents of Berland do. They especially love ...

  2. CodeForces 794 G.Replace All

    CodeForces 794 G.Replace All 解题思路 首先如果字符串 \(A, B\) 没有匹配,那么二元组 \((S, T)\) 合法的一个必要条件是存在正整数对 \((x,y)\), ...

  3. Codeforces 1207 G. Indie Album

    Codeforces 1207 G. Indie Album 解题思路 离线下来用SAM或者AC自动机就是一个单点加子树求和,套个树状数组就好了,因为这个题广义SAM不能存在 \(len[u] = l ...

  4. Codeforces 1097G Vladislav and a Great Legend [树形DP,斯特林数]

    洛谷 Codeforces 这题真是妙的很. 通过看题解,终于知道了\(\sum_n f(n)^k​\)这种东西怎么算. update:经过思考,我对这题有了更深的理解,现将更新内容放在原题解下方. ...

  5. CodeForces 1097G. Vladislav and a Great Legend

    题目简述:给定$n \leq 10^5$个节点的树$T = (V, E)$,令$X \subseteq V$表示一个非空节点集合,定义$f(X)$为包含$X$的最小子树的边数.求 $$ \sum_{\ ...

  6. Codeforces 1097G - Vladislav and a Great Legend(第二类斯特林数+树上背包)

    Codeforces 题目传送门 & 洛谷题目传送门 首先看到这题我的第一反应是:这题跟这题长得好像,不管三七二十一先把 \(k\) 次方展开成斯特林数的形式,\(f(X)^k=\sum\li ...

  7. codeforces 659 G. Fence Divercity 组合数学 dp

    http://codeforces.com/problemset/problem/659/G 思路: f(i,0/1,0/1) 表示到了第i个,要被切的块开始了没有,结束了没有的状态的方案数 递推看代 ...

  8. Codeforces 803 G. Periodic RMQ Problem

    题目链接:http://codeforces.com/problemset/problem/803/G 大致就是线段树动态开节点. 然后考虑到如果一个点还没有出现过,那么这个点显然未被修改,就将这个点 ...

  9. Codeforces 954 G. Castle Defense

    http://codeforces.com/problemset/problem/954/G 二分答案 检验的时候,从前往后枚举,如果发现某个位置的防御力<二分的值,那么新加的位置肯定是越靠后越 ...

随机推荐

  1. cloudstack secondary vm starting

    等1个小时,差不多可以进入虚拟机,看日志/var/log/cloud.log

  2. day69

    昨日回顾: 1 路由层:  1简单配置  2无名分组  3有名分组  4反向解析--模板层,视图层  5路由分发  include  6名称空间   7伪静态 2 作业:  urlpatterns = ...

  3. js中数组的使用

    使用js时候,很多情况下要使用数组.就写写数组中一些常用的方法. js中定义一个数组,一般有以下2种方法. 1. var arr = new Array(3); // 声明数组有3个元素 arr[0] ...

  4. [Lydsy1805月赛]对称数 BZOJ5361

    分析: 这个题,还是蛮有趣的.考虑,如果l,r区间内的所有数出现奇数次,那么[l-1,r]的抑或和等于所得抑或和. 之后怎么维护呢,主席树维护区间抑或和,记得将每个点附上一个ull级别的随机数,之后抑 ...

  5. MSTECHLNK

    MSTECHLNK(微软技术直通车) 时间:2017.12.16地点:微软中关村办公楼天安门会议室

  6. 大数据入门第二十天——scala入门(一)入门与配置

    一.概述 1.什么是scala  Scala是一种多范式的编程语言,其设计的初衷是要集成面向对象编程和函数式编程的各种特性.Scala运行于Java平台(Java虚拟机),并兼容现有的Java程序. ...

  7. 【转】CentOS 5 上安装git

    转自 http://www.cnblogs.com/Neddy/archive/2011/02/28/1967548.html 注意安装的时候 都要以root身份 //先安装git依赖的包 yum i ...

  8. Sterling B2B Integrator与SAP交互 - 02 安装配置

    系统组成: 1. 服务器OS及硬件: OS: Red Hat Enterprise Linux Server release 6.6 Hardware: Virtual Machine, x86_64 ...

  9. JQ_返回顶部

    $(function(){ $('#goto_top_btn').click(function() {var s = $(window).scrollTop(),h = $(window).heigh ...

  10. centos 7 jenkins 部署

    安装jenkins 1.拉取库的配置到本地对应文件 sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redha ...