• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
jacklee404
Never Stop!
博客园    首页    新随笔    联系   管理    订阅  订阅
HBCPC 2020 删点

HBCPC 2020 删点

题目

作者 ICPC Team

单位 北京邮电大学

小河得到了一个包含n个点的无向图。他要选取一个点的集合(可以为空),将其中的点依次删掉。对于选出的这个集合,他还需要选取一个合适的删点顺序,使得删的过程中,任何点在被删掉的时刻依然与至少一个未被删掉的点相连(请参考样例)。

删着删着,他发现,不是所有的集合都能找到一个满足条件的删点顺序。比如,对于下图:

g1.jpg

对于集合{4},{1,4},{2,4},{3,4}都不能找出满足条件的方案,因为无论如何,在删除4的时候,它都不与任何点相连——事实上,4在任何时刻都不与其它点相连。

他希望知道,有多少个不同的集合可以找到一种满足条件的删点顺序。由于方案数可能很大,请输出答案对998244353取模后的结果。

题目保证不会出现自环。

输入格式

第一行两个数字n,m(1≤n,m≤106),表示有n个点和m条边。

接下来m行,每行两个数字x,y(1≤x,y≤n,x=y),表示x和y之间有一条边相连。

输出格式

输出存在符合条件删点顺序的集合个数

样例输入

5 4
1 2
2 3
2 4
3 5

样例输出

31

样例解释

下面是满足条件的31种方案:

∅{1},{2},{3},{4},{5},{1,2},{1,3},{1,4},{1,5},{2,3},{2,4},{2,5},{3,4},{3,5},{4,5},{1,2,3},{1,2,4},{1,2,5},{1,3,4},{1,3,5},{1,4,5},{2,3,4},{2,3,5},{2,4,5},{3,4,5},{1,2,3,4}{1,2,3,5}{1,2,4,5}{1,3,4,5}{2,3,4,5}

以{1,2,5}为例,按照1−2−5的顺序删除即可满足要求,如下图所示:

g2.jpg

唯一一个找不到满足条件删除顺序的集合是{1,2,3,4,5},因为不管怎么删,最后一个点在删除的时候一定不与任何点相邻

代码长度限制

16 KB

Java (javac)

时间限制

6000 ms

内存限制

512 MB

其他编译器

时间限制

3000 ms

内存限制

512 MB

思路

​ 对于图\(G<V, E>\), 考虑每个单独的连通块而言, 我们设删除集合为\(S\), 只要\(S \subset V\), 即\(S\)不包含所有点,这样的序列就是和法的,那么对于一个单独的连通块而言其方案数\(cnt_i = 2^{v_i} - 1\), 其中\(v_i\)为当前连通块内的点数, 那么所有方案数\(CNT = \prod_{i = 1}^{num}(2^{v_i} - 1)\)。

​ 证明对于单独的连通块方案数为\(2^{v_i} - 1\) :构造一种方案,我们考虑当前图的生成树, 构造出一种合法删点顺序对于任何非全集,删点集合始终保持两种状态,有叶子节点和无叶子节点,对于叶子节点显然我们都可以直接删除, 对于非叶子节点,我们可以忽略图中该点,再去删掉别的叶子节点,另外该点若是集合中最后一个点则可以直接删除。由于全集中,我们删去\(n - 1\)个点后,最后一个点不满足条件,所以全集不是合法方案。

Code

#include <bits/stdc++.h>

using i64 = long long;

const int N = 1e6 + 10, M = 2e6 + 10, mod = 998244353;

int n, m;

int h[N], e[M], ne[M], idx;

bool st[N];

int cnt;

void add(int a, int b) {
	ne[idx] = h[a], h[a] = idx, e[idx ++] = b;
}

i64 qmi(i64 a, i64 b) {
	i64 res = 1;
	while (b) {
		if (b & 1) res = res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return res % mod;
}

void dfs(int u) {
	if (st[u]) return;

	st[u] = true;

	cnt ++;

	for (int i = h[u]; ~i; i = ne[i]) {
		int v = e[i];

		if (st[v]) continue;

		dfs(v);
	}
}

int main() {
	memset(h, -1, sizeof h);
	
	std::cin >> n >> m;

	for (int i = 1; i <= m; i ++) {
		int x, y; 
		std::cin >> x >> y;
		add(x, y), add(y, x);
	}

	i64 ans = 1;

	for (int i = 1; i <= n; i ++) {
		if (!st[i]) {
			cnt = 0;
			dfs(i);
			ans = ans * (qmi(2, cnt) - 1) % mod;
		}	
	}

	std::cout << ans;
}

posted on 2023-05-17 17:38  Jack404  阅读(71)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3