[ABC213G] Connectivity 2 题解

[ABC213G] Connectivity 2 题解

套路的经典图上计数题。

考虑枚举和 1 相连的子集 S。答案显然由两部分构成,S 集合和 1 相连的方案数 f(S)S 对于 G 的补集所有的方案数 g(S)。答案就是二者相乘。

显然 g 更好处理。直接枚举集合的边即可。对于 f,图上计数问题不好处理的话通常考虑容斥,所有方案数显然是 g(S),不相连的方案数常见的套路是钦定联通块 T1 相连,记 T 关于 S 的补集是 P,令 P1 不相连,那么 f(S)=g(S)f(T)×g(P)

时间复杂度上瓶颈是枚举 2n 的子集,是 O(3n) 的。

代码:

#include <bits/stdc++.h>
#define N 17
#define int long long
#define mod 998244353
using namespace std;
int n, m;
int mp[N][N];
int f[(1 << N) + 2], g[(1 << N) + 2];
int qpow(int x, int y) {
	int ans = 1;
	while (y) {
		if (y & 1)
			ans = ans * x % mod;
		x = x * x % mod;
		y >>= 1;
	}
	return ans;
}
int ans[N];
signed main() {
	cin >> n >> m;
	for (int i = 0; i < m; i++) {
		int x, y;
		cin >> x >> y;
		--x, --y;
		mp[x][y] = mp[y][x] = 1;
	}
	for (int sta = 0; sta < (1 << n); sta++) {
		for (int i = 0; i < n; i++)
			if ((sta >> i) & 1)
				for (int j = i + 1; j < n; j++)
					if (((sta >> j) & 1) && mp[i][j])
						g[sta]++;
		g[sta] = qpow(2, g[sta]);
	}
	f[1] = 1;
	for (int sta = 3; sta < (1 << n); sta += 2) {
		for (int stb = (sta - 1) & sta; stb; stb = (stb - 1) & sta) 
			f[sta] = (f[sta] + f[stb] * g[sta ^ stb] % mod) % mod;
		f[sta] = (g[sta] - f[sta] + mod) % mod;
	}
	for (int sta = 1; sta < (1 << n); sta++) {
		f[sta] = f[sta] * g[((1 << n) - 1) ^ sta] % mod;
		for (int i = 0; i < n; i++)
			if ((sta >> i) & 1)
				ans[i] = (ans[i] + f[sta]) % mod;		
	}
	for (int i = 1; i < n; i++)
		cout << ans[i] << "\n";
	return 0;	
} 
posted @   长安19路  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示