@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 定理,得到:

\[\frac{(n - |S| - 1)!}{(\sum_{i\in S}(d_i - 2) - 1)!\times \prod_{i\not \in S}(d_i - 1)!}
\]

不过 x' 的出边并不是全部相同。对于 x' 还有个系数 \(\frac{(\sum_{i\in S}(d_i - 2))!}{\prod_{i\in S}(d_i - 2)!}\),表示邻接边的分配方案。

因此整合得到:

\[\begin{aligned}
&\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) 做法:

\[\begin{aligned}
&\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的更多相关文章

  1. [AtCoder Code Festival 2017 QualB D/At3575] 101 to 010 - dp

    [Atcoder Code Festival 2017 QualB/At3575] 101 to 010 有一个01序列,每次可以选出一个101,使其变成010,问最优策略下能操作几次? 考虑像 11 ...

  2. Atcoder CODE FESTIVAL 2017 qual B D - 101 to 010 dp

    题目链接 题意 对于一个\(01\)串,如果其中存在子串\(101\),则可以将它变成\(010\). 问最多能进行多少次这样的操作. 思路 官方题解 转化 倒过来考虑. 考虑,最终得到的串中的\(' ...

  3. 题解【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 串 ...

  4. 【题解】Popping Balls AtCoder Code Festival 2017 qual B E 组合计数

    蒟蒻__stdcall终于更新博客辣~ 一下午+一晚上=一道计数题QAQ 为什么计数题都这么玄学啊QAQ Prelude 题目链接:这里是传送门= ̄ω ̄= 下面我将分几个步骤讲一下这个题的做法,大家不 ...

  5. AtCoder Code Festival 2017 Team Relay J - Indifferent

    题目大意:共$2n$个价格$p_i$.两人轮流取.你每次取最大的,对方每次随机取.问你取的期望和是多少. 题解:从小到大排序,$\sum\limits_{i=0}^{2n-1} \frac{i*p_i ...

  6. atcoder/CODE FESTIVAL 2017 qual B/B(dfs染色判断是否为二分图)

    题目链接:http://code-festival-2017-qualb.contest.atcoder.jp/tasks/code_festival_2017_qualb_c 题意:给出一个含 n ...

  7. Atcoder CODE FESTIVAL 2017 qual C D - Yet Another Palindrome Partitioning 回文串划分

    题目链接 题意 给定一个字符串(长度\(\leq 2e5\)),将其划分成尽量少的段,使得每段内重新排列后可以成为一个回文串. 题解 分析 每段内重新排列后是一个回文串\(\rightarrow\)该 ...

  8. Atcoder CODE FESTIVAL 2017 qual C C - Inserting 'x' 回文串

    题目链接 题意 给定字符串\(s\),可以在其中任意位置插入字符\(x\). 问能否得到一个回文串,若能,需插入多少个\(x\). 思路 首先统计出现次数为奇数的字符\(cnt\). \(cnt\ge ...

  9. Atcoder CODE FESTIVAL 2017 qual B E - Popping Balls 组合计数

    题目链接 题意 \(A+B\)个球排成一行,左边\(A\)个为红球,右边\(B\)个为蓝球. 最开始可以选择两个数\(s,t\),每次操作可以取左起第\(1\)或\(s\)或\(t\)个球.问有多少种 ...

随机推荐

  1. zabbix 自动发现主机并关联模板

    一.自动发现添加主机 1.利用agent自动发现主机 Configuration - Discovery -Create discovery rule 2.将自动发现的主机关联模板 Configura ...

  2. 机器学习决策树ID3算法,手把手教你用Python实现

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是机器学习专题的第21篇文章,我们一起来看一个新的模型--决策树. 决策树的定义 决策树是我本人非常喜欢的机器学习模型,非常直观容易理解 ...

  3. 避免scrollview内部控件输入时被键盘遮挡,监听键盘弹起,配合做滚动

    1,监听键盘 2,根据当前键盘弹起高度与控件的底部位置计算滑动距离 3,根据滑动距离在键盘弹起和隐藏是分别设置动画完成滑动     实现: 1,监听键盘使用   #pragma mark - 键盘监听 ...

  4. C# 数据操作系列 - 18 让Dapper更强的插件

    0. 前言 在前一篇中我们讲到了Dapper的应用,但是给我们的感觉Dapper不像个ORM更像一个IDbConnection的扩展.是的,没错.在实际开发中我们经常用Dapper作为对EF Core ...

  5. eatwhatApp开发实战(七)

    之前我们为app添加了读取本地数据的功能和删除的功能.本次我们来将listview上item项的触控修改为item项上单一控件的触控事件.用item项上的button来实现删除数据. 先上布局: &l ...

  6. Druid数据库连接池的使用

    Druid  阿里提供的数据库连接池,集以上连接池优点于一身,开发使用此连接池 使用配置文件方式获取Druid数据库连接池 TestDruid package com.aff.connection; ...

  7. 使用RTL进行硬件模型编程的局限性

    https://mp.weixin.qq.com/s/Nj_d3hwgNX4kWVtKsqMSWg   ​​   硬件模型编程,即Hardware Model Programming.在RTL抽象级别 ...

  8. 收藏!如何有效实施devops?

    当今IT行业的竞争日益激烈,各家公司都在寻找优化软件研发过程的方法,因为交付比对手更具竞争力的产品已经越发成为一件成本高昂的事情.这也是DevOps发挥作用的地方,因为它可以在工程管理的各个方面提供帮 ...

  9. Linux内存管理—详细讲解

    摘要:本章首先以应用程序开发者的角度审视Linux的进程内存管理,在此基础上逐步深入到内核中讨论系统物理内存管理和内核内存的使用方法.力求从外到内.水到渠成地引导网友分析Linux的内存管理与使用.在 ...

  10. Jmeter(七) - 从入门到精通 - 建立数据库测试计划实战<MySQL数据库>(详解教程)

    1.简介 在实际工作中,我们经常会听到数据库的性能和稳定性等等,这些有时候也需要测试工程师去评估和测试,上一篇文章宏哥主要介绍了jmeter连接和创建数据库测试计划的过程,宏哥在文中通过示例和代码非常 ...