@loj - 2250@ 「ZJOI2017」仙人掌
@题目描述@
如果一个无自环无重边无向连通图的任意一条边最多属于一个简单环,我们就称之为仙人掌。所谓简单环即不经过重复的结点的环。

现在九条可怜手上有一张无自环无重边的无向连通图,但是她觉得这张图中的边数太少了, 所以她想要在图上连上一些新的边。同时为了方便的存储这张无向图,图中的边数又不能太多。 经过权衡,她想要加边后得到的图为一棵仙人掌。
不难发现合法的加边方案有很多,可怜想要知道总共有多少不同的加边方案。
两个加边方案是不同的当且仅当一个方案中存在一条另一个方案中没有的边。
输入格式
多组数据,第一行输入一个整数 T 表示数据组数。
每组数据第一行输入两个整数 n, m,表示图中的点数与边数。
接下来 m 行,每行两个整数 u, v(1 <= u, v <= n, u ≠ v) 表示图中的一条边。
保证输入的图联通且没有自环与重边。
输出格式
对于每组数据,输出一个整数表示方案数,当然方案数可能很大,请对 998244353 取模后输出。
样例
样例输入
2
3 2
1 2
1 3
5 4
1 2
2 3
2 4
1 5
样例输出
2
8
数据范围与提示
1 <= ∑n <= 5*10^5,1 <= ∑m <= 10^6。
@solution@
如果所有简单环都没有公共边,则一个图是仙人掌。
我们跑一遍 tarjan,将所有返祖边对应的树链标记加一。最后如果有一条边标记 > 1 则不为仙人掌。
然后初始图肯定得是一棵仙人掌。显然我们不可能跨越环连边,于是可以把所有环上的边去掉。
剩下的图变成了一棵不相交的森林。森林之间不能连边,我们只能在树上连求方案数,再把所有树的方案数相乘。
怎么求一棵树连成仙人掌的方案数?一样要求所有简单环都没有公共边,则我们相当于选出若干条没有公共边的链,求方案数。
接下来?树形 dp?貌似没有什么高效的 dp 方法。
因为没有重边,所以我们选出来的链长度 > 1。我们再把问题进一步转化:将没有被选在链中去的那些边单独作一条链,则用边不相交的链覆盖树上所有边的方案唯一对应选出若干条没有公共边的链的方案。
接着考虑每个点的贡献,设点 i 的度数为 d[i]。则我们可以将 i 连出去的边两两配对(也可以不配对),表示 i 所相邻的配对的那些边在同一条链里。
记 f[i] 表示 i 条边互相匹配的方案数,则最终答案为 f[d[i]] 之积。
f[i] 很好求,有递推式 f[i] = f[i-1] + (i-1)*f[i-2]。前者表示不匹配,后者表示选一个匹配。
@accepted code@
#include<cstdio>
#define rep(G, x) for(Graph::edge *p = G.adj[x];p;p = p->nxt)
const int MAXN = 500000;
const int MAXM = 1000000;
const int MOD = 998244353;
struct Graph{
struct edge{
int to; edge *nxt;
}edges[2*MAXM + 5], *adj[MAXN + 5], *ecnt;
void clear(int n) {
ecnt = &edges[0];
for(int i=1;i<=n;i++)
adj[i] = NULL;
}
void addedge(int u, int v) {
edge *p = (++ecnt);
p->to = v, p->nxt = adj[u], adj[u] = p;
p = (++ecnt);
p->to = u, p->nxt = adj[v], adj[v] = p;
}
}G1, G2;
int f[MAXN + 5];
void init() {
f[0] = f[1] = 1;
for(int i=2;i<=MAXN;i++)
f[i] = (f[i - 1] + 1LL * (i - 1) * f[i - 2] % MOD) % MOD;
}
bool flag;
int d[MAXN + 5], s[MAXN + 5];
int dfn[MAXN + 5], dcnt;
void clear(int n) {
G1.clear(n), G2.clear(n);
for(int i=1;i<=n;i++)
d[i] = s[i] = dfn[i] = 0;
dcnt = 0, flag = true;
}
void tarjan(int x, int fa) {
dfn[x] = (++dcnt);
rep(G1, x) {
if( p->to == fa ) continue;
if( dfn[p->to] ) {
if( dfn[p->to] < dfn[x] )
s[x]++, s[p->to]--;
}
else tarjan(p->to, x), G2.addedge(x, p->to);
}
}
int dfs(int x, int fa) {
int ret = s[x];
rep(G2, x) {
if( p->to == fa ) continue;
int del = dfs(p->to, x);
ret += del;
if( del == 0 )
d[x]++, d[p->to]++;
else if( del >= 2 )
flag = false;
}
return ret;
}
void solve() {
int n, m; scanf("%d%d", &n, &m), clear(n);
for(int i=1;i<=m;i++) {
int u, v; scanf("%d%d", &u, &v);
G1.addedge(u, v);
}
tarjan(1, 0), dfs(1, 0);
if( flag ) {
int ans = 1;
for(int i=1;i<=n;i++)
ans = 1LL * ans * f[d[i]] % MOD;
printf("%d\n", ans);
}
else puts("0");
}
int main() {
init(); int T; scanf("%d", &T);
while( T-- ) solve();
}
@details@
坚定了我对于 ZJOI 的题都是不可做的题的决心。
@loj - 2250@ 「ZJOI2017」仙人掌的更多相关文章
- 「ZJOI2017」仙人掌
「ZJOI2017」仙人掌 题目大意: 给定一张无向联通图,求有多少种本质不同的不加重边的加边方案使得新图是个仙人掌. 解题思路: 如果原来的图不是仙人掌,那么答案就是 \(0\) ,否则求出这个仙人 ...
- Loj #2570. 「ZJOI2017」线段树
Loj #2570. 「ZJOI2017」线段树 题目描述 线段树是九条可怜很喜欢的一个数据结构,它拥有着简单的结构.优秀的复杂度与强大的功能,因此可怜曾经花了很长时间研究线段树的一些性质. 最近可怜 ...
- Loj #2192. 「SHOI2014」概率充电器
Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...
- Loj #3096. 「SNOI2019」数论
Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...
- Loj #3093. 「BJOI2019」光线
Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...
- Loj #3089. 「BJOI2019」奥术神杖
Loj #3089. 「BJOI2019」奥术神杖 题目描述 Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的 ...
- Loj #2542. 「PKUWC2018」随机游走
Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...
- Loj #3059. 「HNOI2019」序列
Loj #3059. 「HNOI2019」序列 给定一个长度为 \(n\) 的序列 \(A_1, \ldots , A_n\),以及 \(m\) 个操作,每个操作将一个 \(A_i\) 修改为 \(k ...
- Loj #3056. 「HNOI2019」多边形
Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...
随机推荐
- JavaScript中[]+[] 、[]+{}、{}+[]、{}+{}的结果分析
看到这样一个问题:{} + [] 的结果是多少? 一脸懵逼.. 于是在chrome控制台运行 {} + [] 和用 console.log({} + []) 输出,发现结果不一样.. 于是,把各种可能 ...
- 组合数学起步-排列计数[ZJOI2010][BZOJ2111]
<题面> 数据范围:$1 \leq N \leq 10^6, P \leq 10^9 $ 这个题…… 以为是排列,其实是组合 题目中说是从所有排列中找到Magic的,就是 $p_{i/2} ...
- 适配器模式--在NBA我需要翻译
适配器模式:将一个类的接口转换成客户希望的另外一个接口.Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 在软件开发中,也就是系统的数据和行为都正确,但接口不符时,我们应 ...
- CesiumLab V1.2 新功能 倾斜数据处理
一转眼又是一周的时间,我们的实验室功能又强大了. 照旧我们先放毒,放图,图,太晚了,字都敲不到一起了 lod以及包围盒 大雁塔实例,按楼层单体化 倾斜数据处理参数设置 简单介绍一下 Ces ...
- 直接删除mysql的日志导致mysql无法启动
--02T08::.750000Z [Warning] [MY-] [Server] 'NO_ZERO_DATE', 'NO_ZERO_IN_DATE' and 'ERROR_FOR_DIVISION ...
- Neo4j与ElasticSearch数据同步
Neo4j与ElasticSearch数据同步 针对节点删除,加了一些逻辑,代码地址 背景 需要强大的检索功能,所有需要被查询的数据都在neo4j. 方案 在Server逻辑中直接编写.后端有一个St ...
- php 获取一张图片所有点的颜色值
image_all_rgb.php <?php //similar_text($numStr, $val, $pre); //计算两个字符串的相似度 //print_r($pre); $imgP ...
- Leetcode643.Maximum Average Subarray I子数组的最大平均数1
给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数. 示例 1: 输入: [1,12,-5,-6,50,3], k = 4 输出: 12.75 解释: 最大平均数 (12- ...
- tyvj 1864 守卫者的挑战
传送门 解题思路 dp[i][j][k]表示前i个挑战,赢了j场,现在还有k个包的获胜概率. 转移方程: dp[i+1][j+1][k+a[i]] += p[i+1]*dp[i][j][k] (k+a ...
- Windows下更改pip镜像源
其实学习是一个逐步探索的过程.今天因为把带有中文的Python安装路径给改了,结果带来很大的麻烦,导致在命令行输入vietualenv和其他一些第三方模块都出现Fatal error in launc ...