原文链接https://www.cnblogs.com/zhouzhendong/p/CF1109D.html

题意

所有边权都是 [1,m] 中的整数的所有 n 个点的树中,点 a 到点 b 的距离恰好是 m 的有几个。

$$n,m\leq 10^6$$

题解

首先显然 a 和 b 的具体值是没用的。

于是我们就可以直接计数:

枚举树链 ab 上除了 a 和 b 有几个节点,假设是 i 个节点,那么这种情况下的方案总数是多少?

首先,ab 路径上 i+1 条 [1,m] 的边的和是 m ,共有 $\binom{m-1}{i}$ 种边权的取值;

然后,ab 路径上共有 i 个点,方案数是从剩下的 n-2 个点种选出 i 个并排列,即 $\binom{n-2}i i!$ 。

然后,剩下的 n-2-i 条边每条都有 m 种取值,方案数是 $m^{n-2-i}$ 。

最后,考虑生成树的个数,用 prufer 序列的结论推一推就可以知道方案数是 $n^{n-3-i}(i+2)$ 。

所以答案是

$$\sum_{i=0}^{n-2} \binom{n-2}{i}\binom{m-1}{i}m^{n-2-i}n^{n-3-i}i!(i+2)$$

UPD(2019-03-04): 更新一下关于那个 prufer 编码推出的公式的证明:

prufer 编码有几个性质:

1. 假如是 n 个点,那么编码长度为 n-2 ,且每一个位置可以放 1~n 之间的任意数,每一个 prufer 编码与每一个树一一对应。

2. 假设树中一个点 x 的度是 d[x] ,那么在对应的 prufer 编码中,x 出现 d[x]-1 次。

假设我们有 n 个点,被分成了 k 个点集,每个点集里的点已经连通,不同点集之间的点两两无边,现在我们要在这个 n 个点 n-k 条边的基础上求生成树个数。设第 i 个点集包含的点数为 size[i] 。

那么,如果我们把这 k 个点集每一个点都看作一个点,做一个 k 个点的生成树,那么有 $k^{k-2}$ 种方案;但是由于这里的每一个点都是一个点集,所以假设它是点集 i,那么从他连出去的每一条边的属于集合i的端点,都有 size[i] 种选法。也就是说,对于一个 k 个点的 prufer 编码,假设在这个编码中,数字 i 出现了 c[i] 次,那么这个编码对应到原树上就会贡献 $\prod_{i=1}^k size[i] ^ {c[i]+1} $ 次。

我们把每一个 "c[i]+1" 中多出来的 1 提出,看作常量,我们来对于所有 prufer 编码求贡献总和:

$$\sum_{P是一个prufer编码}\ \ \ \ \ \prod_{i=1}^k size[i] ^ {c[i]}$$ 。

考虑到这个prufer编码的每一位选择第 i 个点集,就会对乘积有 $size[i]$ 的贡献,根据乘法分配律,我们可以得到上面的那个式子就是: $(\sum_{i=1}^k size[i])^{k-2} = n ^ {k-2}$ 。

再乘上之前提出的东西,所以答案就是:

$$(\sum_{i=1}^k size[i])^{k-2} \cdot \prod_{i=1}^k size[i] $$

本题要求的那个,只是这个模型的弱化版。至此已经可以解决这个问题了。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL read(){
LL x=0,f=0;
char ch=getchar();
while (!isdigit(ch))
f|=ch=='-',ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
const int N=1000005,mod=1e9+7;
int n,m,a,b;
int Fac[N],Inv[N];
int C(int n,int m){
if (m>n||m<0)
return 0;
return (LL)Fac[n]*Inv[m]%mod*Inv[n-m]%mod;
}
int Pow(int x,int y){
if (y<0)
return Pow(x,y+mod-1);
int ans=1;
for (;y;y>>=1,x=(LL)x*x%mod)
if (y&1)
ans=(LL)ans*x%mod;
return ans;
}
void init(int n){
for (int i=Fac[0]=1;i<=n;i++)
Fac[i]=(LL)Fac[i-1]*i%mod;
Inv[n]=Pow(Fac[n],mod-2);
for (int i=n;i>=1;i--)
Inv[i-1]=(LL)Inv[i]*i%mod;
}
void Add(int &x,int y){
if ((x+=y)>=mod)
x-=mod;
}
int main(){
n=read(),m=read(),a=read(),b=read();
init(max(n,m));
int ans=0;
for (int i=0;i<=n-2;i++)
Add(ans,(LL)C(n-2,i)*C(m-1,i)%mod*Fac[i]%mod
*Pow(m,n-2-i)%mod*Pow(n,n-3-i)%mod*(i+2)%mod);
cout<<ans<<endl;
return 0;
}

  

Codeforces 1109D. Sasha and Interesting Fact from Graph Theory 排列组合,Prufer编码的更多相关文章

  1. Codeforces 1109D. Sasha and Interesting Fact from Graph Theory

    Codeforces 1109D. Sasha and Interesting Fact from Graph Theory 解题思路: 这题我根本不会做,是周指导带飞我. 首先对于当前已经有 \(m ...

  2. Codeforces 1109D Sasha and Interesting Fact from Graph Theory (看题解) 组合数学

    Sasha and Interesting Fact from Graph Theory n 个 点形成 m 个有标号森林的方案数为 F(n, m) = m * n ^ {n - 1 - m} 然后就 ...

  3. CF1109D Sasha and Interesting Fact from Graph Theory

    CF1109D Sasha and Interesting Fact from Graph Theory 这个 \(D\) 题比赛切掉的人基本上是 \(C\) 题的 \(5,6\) 倍...果然数学计 ...

  4. Sasha and Interesting Fact from Graph Theory CodeForces - 1109D (图论,计数,Caylay定理)

    大意: 求a->b最短路长度为m的n节点树的个数, 边权全部不超过m 枚举$a$与$b$之间的边数, 再由拓展$Caylay$定理分配其余结点 拓展$Caylay$定理 $n$个有标号节点生成k ...

  5. Codeforces1113F. Sasha and Interesting Fact from Graph Theory(组合数学 计数 广义Cayley定理)

    题目链接:传送门 思路: 计数.树的结构和边权的计数可以分开讨论. ①假设从a到b的路径上有e条边,那么路径上就有e-1个点.构造这条路径上的点有$A_{n-2}^{e-1}$种方案: ②这条路径的权 ...

  6. CF1109DSasha and Interesting Fact from Graph Theory(数数)

    题面 传送门 前置芝士 Prufer codes与Generalized Cayley's Formula 题解 不行了脑子已经咕咕了连这么简单的数数题都不会了-- 首先这两个特殊点到底是啥并没有影响 ...

  7. Codeforces Round #485 (Div. 2) F. AND Graph

    Codeforces Round #485 (Div. 2) F. AND Graph 题目连接: http://codeforces.com/contest/987/problem/F Descri ...

  8. Codeforces 703D Mishka and Interesting sum 离线+树状数组

    链接 Codeforces 703D Mishka and Interesting sum 题意 求区间内数字出现次数为偶数的数的异或和 思路 区间内直接异或的话得到的是出现次数为奇数的异或和,要得到 ...

  9. CodeForces 840B - Leha and another game about graph | Codeforces Round #429(Div 1)

    思路来自这里,重点大概是想到建树和无解情况,然后就变成树形DP了- - /* CodeForces 840B - Leha and another game about graph [ 增量构造,树上 ...

随机推荐

  1. Windows + Ubuntu 16.04 双系统安装详细教程

    Windows + Ubuntu 16.04 双系统安装详细教程 2018年01月28日 16:43:19 flyyufenfei 阅读数:165619   发现了一篇好教程,果断转载了,以后用得着时 ...

  2. 关于申请GMS认证来使用谷歌的一些服务应用及闭源API

    房间内的主要大象正在获取Google移动服务(GMS)的许可证.这是指预先选择的谷歌应用程序阵列,它将谷歌本身的精髓包含在其配置中 -  Google搜索,YouTube,Gmail,Chrome,G ...

  3. 使用ServletContext对象读取资源文件

    备注:本文以properties文件为例 一.通过ServletContext读取文件 1.通过ServletContext读取放置在src下的properties文件 package com; im ...

  4. 关于win10企业版在极域电子教室软件 v4.0 2015 豪华版的全屏控制下如何取得自由

    注.可能因为系统和软件的缘故无法实现 背景 由于在听课过程过于自闭,于是想自己去网上搜点东西看下 于是 经过了一番乱搞 逐渐摸索出了现方法. 方案1: 大力出奇迹 由于电脑在刚刚进入的状态的时候有段时 ...

  5. Django模板

    Django模板系统 官方文档 常用语法 只需要记住两种特殊符号: {{  }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 变量 { 变量名 }} 变量名由字母数字和下划线组成. 点 ...

  6. BZOJ2870 最长道路

    题意:给定树,有点权.求一条路径使得最小点权 * 总点数最大.只需输出这个最大值.5w. 解:树上路径问题,点分治. 考虑合并两个子树的时候,答案的形式是val1 * (d1 + d2),当1是新插入 ...

  7. host-only局域网络

    在网桥配置的情况下设置: 网桥配置链接 配置前: 配置后: vi /etc/sysconfig/network-scripts/ifcfg-eth0 这里是使用static静态配置,具体网络配置及声明 ...

  8. SQL随记(二)

    1.purge关键字:可以清除oracle 回收站(recyclebin)中的表和索引并释放与其相关的空间,还可清空回收站,或者清除表空间中记录的已删除的部分表空间.但是purge后不能回滚和恢复. ...

  9. 第六节:反射(几种写法、好处和弊端、利用反射实现IOC)

    一. 加载dll,读取相关信息 1. 加载程序集的三种方式 调用Assembly类下的三个方法:Load.LoadFile.LoadFrom. //1.1 Load方法:动态默认加载当前路径下的(bi ...

  10. 第七节:语法总结(1)(自动属性、out参数、对象初始化器、var和dynamic等)

    一. 语法糖简介   语法糖也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方 ...