@atcoder - CODE FESTIVAL 2017 Elimination Tournament Round 3 F@ Unicyclic Graph Counting
@description@
求有多少 n 点 n 边的无向连通图,满足第 i 个点的度数为 \(d_i\)。
@solution@
如果是树显然就 prufer 定理;基环树就考虑拓展一下。
枚举环上的点集合 S,则环内部能够连出的方案数为 \(\frac{(|S| - 1)!}{2}\)(注意环的大小 \(|S| \geq 3\))。
接着,将环缩成一个新点 x',则它的度数为 \(d_{x'} = \sum_{i\in S}(d_i - 2)\)(注意 \(d_i \geq 2\))。
对缩点后的新图运用 prufer 定理,得到:
\]
不过 x' 的出边并不是全部相同。对于 x' 还有个系数 \(\frac{(\sum_{i\in S}(d_i - 2))!}{\prod_{i\in S}(d_i - 2)!}\),表示邻接边的分配方案。
因此整合得到:
&\frac{(|S| - 1)!}{2}\times \frac{(n - |S| - 1)!}{(\sum_{i\in S}(d_i - 2) - 1)!\times \prod_{i\not \in S}(d_i - 1)!}\times \frac{(\sum_{i\in S}(d_i - 2))!}{\prod_{i\in S}(d_i - 2)!}\\
=&\frac{(|S| - 1)!}{2}\times \frac{(n - |S| - 1)!}{\prod_{i}(d_i - 1)!}\times (\sum_{i\in S}(d_i - 2)) \times \prod_{i\in S}(d_i - 1)
\end{aligned}
\]
把 \((|S|, \sum(d_i - 2))\) 当作状态做一个 O(n^3) 的 dp 求 \(\prod_{i\in S}(d_i - 1)\) 即可。
特判 n 个点连成一个大环的情况。
@accpeted code@
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 300;
const int MOD = int(1E9) + 7;
const int INV2 = (MOD + 1) / 2;
inline int add(int x, int y) {return (x + y >= MOD ? x + y - MOD : x + y);}
inline int sub(int x, int y) {return (x - y < 0 ? x - y + MOD : x - y);}
inline int mul(int x, int y) {return 1LL * x * y % MOD;}
int pow_mod(int b, int p) {
int ret = 1;
for(int i=p;i;i>>=1,b=mul(b,b))
if( i & 1 ) ret = mul(ret, b);
return ret;
}
int fct[2*MAXN + 5], ifct[2*MAXN + 5];
void init() {
fct[0] = 1; for(int i=1;i<=2*MAXN;i++) fct[i] = mul(fct[i - 1], i);
for(int i=0;i<=2*MAXN;i++) ifct[i] = pow_mod(fct[i], MOD - 2);
}
int dp[2][MAXN + 5][MAXN + 5];
int d[MAXN + 5], N;
int main() {
init(), scanf("%d", &N);
for(int i=1;i<=N;i++)
scanf("%d", &d[i]), d[i]--;
int tot = 0; dp[0][0][0] = 1;
for(int i=1;i<=N;i++) {
if( d[i] ) {
for(int j=0;j<i;j++)
for(int k=0;k<=tot;k++)
dp[1][j][k] = dp[0][j][k];
for(int j=0;j<i;j++)
for(int k=0;k<=tot;k++)
dp[0][j+1][k+d[i]-1] = add(dp[0][j+1][k+d[i]-1], mul(d[i], dp[1][j][k]));
tot += d[i] - 1;
}
}
int ans = mul(mul(fct[N-1], INV2), dp[0][N][0]), tmp = 1;
for(int i=1;i<=N;i++) tmp = mul(tmp, ifct[d[i]]);
for(int i=3;i<N;i++)
for(int j=1;j<=tot;j++) {
int coef = mul(mul(fct[i-1], INV2), mul(fct[N-i-1], tmp));
ans = add(ans, mul(mul(coef, j), dp[0][i][j]));
}
printf("%d\n", ans);
}
@details@
如果是不带度数限制基环树,还是用的 prufer 序列,和上述方法相同(貌似矩阵树解不了的样子。。。)
本题还有一个更快的 O(n^2) 做法:
&\frac{(|S| - 1)!}{2}\times \frac{(n - |S| - 1)!}{(\sum_{i\in S}(d_i - 2) - 1)!\times \prod_{i\not \in S}(d_i - 1)!}\times \frac{(\sum_{i\in S}(d_i - 2))!}{\prod_{i\in S}(d_i - 2)!}\\
=&\frac{(|S| - 1)!\times (n - |S| - 1)!}{2}\times \frac{\sum_{i\in S}(d_i - 2)}{\prod_{i\not \in S}(d_i - 1)!\prod_{i \in S}(d_i - 2)!}\\
=&\frac{(|S| - 1)!\times (n - |S| - 1)!}{2}\times \sum_{i\in S}\frac{1}{\prod_{j\not \in S}(d_j - 1)!\times \prod_{j \in S, j\not = i}(d_j - 2)!\times (d_i - 3)}
\end{aligned}
\]
只需要存状态 \(|S|\) 以及是否贡献了 \(\frac{1}{d_i - 3}\)。一样需要特判。
@atcoder - CODE FESTIVAL 2017 Elimination Tournament Round 3 F@ Unicyclic Graph Counting的更多相关文章
- [AtCoder Code Festival 2017 QualB D/At3575] 101 to 010 - dp
[Atcoder Code Festival 2017 QualB/At3575] 101 to 010 有一个01序列,每次可以选出一个101,使其变成010,问最优策略下能操作几次? 考虑像 11 ...
- Atcoder CODE FESTIVAL 2017 qual B D - 101 to 010 dp
题目链接 题意 对于一个\(01\)串,如果其中存在子串\(101\),则可以将它变成\(010\). 问最多能进行多少次这样的操作. 思路 官方题解 转化 倒过来考虑. 考虑,最终得到的串中的\(' ...
- 题解【AtCoder - CODE FESTIVAL 2017 qual B - D - 101 to 010】
题目:https://atcoder.jp/contests/code-festival-2017-qualb/tasks/code_festival_2017_qualb_d 题意:给一个 01 串 ...
- 【题解】Popping Balls AtCoder Code Festival 2017 qual B E 组合计数
蒟蒻__stdcall终于更新博客辣~ 一下午+一晚上=一道计数题QAQ 为什么计数题都这么玄学啊QAQ Prelude 题目链接:这里是传送门= ̄ω ̄= 下面我将分几个步骤讲一下这个题的做法,大家不 ...
- AtCoder Code Festival 2017 Team Relay J - Indifferent
题目大意:共$2n$个价格$p_i$.两人轮流取.你每次取最大的,对方每次随机取.问你取的期望和是多少. 题解:从小到大排序,$\sum\limits_{i=0}^{2n-1} \frac{i*p_i ...
- atcoder/CODE FESTIVAL 2017 qual B/B(dfs染色判断是否为二分图)
题目链接:http://code-festival-2017-qualb.contest.atcoder.jp/tasks/code_festival_2017_qualb_c 题意:给出一个含 n ...
- Atcoder CODE FESTIVAL 2017 qual C D - Yet Another Palindrome Partitioning 回文串划分
题目链接 题意 给定一个字符串(长度\(\leq 2e5\)),将其划分成尽量少的段,使得每段内重新排列后可以成为一个回文串. 题解 分析 每段内重新排列后是一个回文串\(\rightarrow\)该 ...
- Atcoder CODE FESTIVAL 2017 qual C C - Inserting 'x' 回文串
题目链接 题意 给定字符串\(s\),可以在其中任意位置插入字符\(x\). 问能否得到一个回文串,若能,需插入多少个\(x\). 思路 首先统计出现次数为奇数的字符\(cnt\). \(cnt\ge ...
- Atcoder CODE FESTIVAL 2017 qual B E - Popping Balls 组合计数
题目链接 题意 \(A+B\)个球排成一行,左边\(A\)个为红球,右边\(B\)个为蓝球. 最开始可以选择两个数\(s,t\),每次操作可以取左起第\(1\)或\(s\)或\(t\)个球.问有多少种 ...
随机推荐
- create-react-app ios8系统中页面空白/样式错乱问题
1. 空白问题 因为缺少polyfill 在public/index.html 中引入如下js <script src="https://cdnjs.cloudflare.com/aj ...
- Spring 由构造函数自动装配
Spring 由构造函数自动装配,这种模式与 byType 非常相似,但它应用于构造器参数. Spring 容器看作 beans,在 XML 配置文件中 beans 的 autowire 属性设置为 ...
- poj1149 经典建模
http://wenku.baidu.com/view/0ad00abec77da26925c5b01c.html 以上内容均为转载 #include<queue> #include< ...
- POJ3255
题目链接:http://poj.org/problem?id=3255 解题思路: 昨晚两点多睡不着翻起来刷<挑战>的题,结果遇到这道求次短路的题,一脸懵逼.想了半小时没什么思路就看他的解 ...
- 手机短号(hdu2081)
这里字符串的输入用gets_s()函数. #include<stdio.h> using namespace std; int main() { int N; scanf_s(" ...
- vue端口号被占用
今天在启动一个Vue项目的时候,遇到了一个问题. 得知是Vue项目端口号占用的问题. 解决方法: 换一个端口号. 在调用 npm run dev 的时候,实际上是在调用根目录下的 package ...
- Rocket - debug - Example: Quick Access
https://mp.weixin.qq.com/s/SxmX-CY2tqvEqZuAg-EXiQ 介绍riscv-debug的使用实例:配置Quick Access功能. 1. Quick Acce ...
- Rocket - util - Timer
https://mp.weixin.qq.com/s/Z4JJhZ_jL1lqF1nf_orq9A 简单介绍Timer的实现. 1. 基本功能 实现定时器的功能. 2. Ti ...
- jchdl - GSL实例 - DFlipFlop(D触发器)
https://mp.weixin.qq.com/s/7N3avTxTd2ZUnAcKg4w3Ig D触发器对边沿敏感,只有当相应的边沿出现时,才会触发D的值传播到输出Q. 引自:htt ...
- C# winform 学习(三)
目标 1.windows程序简介 2.窗体的常用属性和事件 3.显示消息框 4.多窗体应用 一.程序简介 1.特点:所见即所得,通过事件实现用户与界面的交互 2.程序结构 1)窗体文件(每个窗体至少有 ...