AtCoder Beginner Contest 213G - Connectivity 2(状压dp神仙题)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder Beginner Contest 213G - Connectivity 2(状压dp神仙题)相关的知识,希望对你有一定的参考价值。

LINK

题意

给定简单无向图 G = ( V , E ) G=(V,E) G=(V,E),点的编号从 1 1 1 ∣ V ∣ = n |V|=n V=n.对于 k = 2.. n k=2..n k=2..n,求 H = ( V , E ′ ⊆ E ) H=(V,E′⊆E) H=(V,EE) 的个数,使得 1 1 1 k k k 连通。

n ≤ 17 , m < = n ∗ ( n − 1 ) 2 n≤17,m<=\\frac{n*(n-1)}{2} n17,m<=2n(n1)


考虑最后图的状态,点 1 1 1和点 k k k处于同一个连通块,这个连通块到其他点没有边

定义全集 U = ( 1 < < n ) − 1 U=(1<<n)-1 U=(1<<n)1

考虑枚举最后的这个点集 s s s包含点 1 , k 1,k 1,k,定义 c n t ( s ) cnt(s) cnt(s)表示子集 s s s中包含的边

f ( S ) f(S) f(S)表示利用这 c n t ( S ) cnt(S) cnt(S)条边把 S S S连通的方案数

答案为

a n s ( k ) = ∑ 1 ∈ S , k ∈ S f [ S ] ∗ 2 c n t ( U − S ) ans(k)=\\sum\\limits_{1\\in S,k\\in S}f[S]*2^{cnt(U-S)} ans(k)=1S,kSf[S]2cnt(US)

这样显然是正确的,因为 S S S内部连通,而 S S S点集和外面点之间的边都断掉,整下的 c n t ( U − S ) cnt(U-S) cnt(US)条边怎么放都可以

怎么计算 f ( S ) ? f(S)? f(S)?正着转移有重复,反着考虑

f ( S ) = 2 c n t ( S ) − ∑ T ∈ S & & S ! = T f ( T ) ∗ 2 S − T f(S)=2^{cnt(S)}-\\sum\\limits_{T\\in S\\&\\&S!=T}f(T)*2^{S-T} f(S)=2cnt(S)TS&&S!=Tf(T)2ST

但是考虑到在不合法方案中 S S S中存在多个连通块,一个方案会在多个 T T T中被计算

所以我们任取其中一点,只计算这个点所在的连通块就是唯一的

这样的分割就是唯一的

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
const int maxn = 1<<21;
int n,m,f[1<<17],g[1<<17],a[17*17],b[17*17],bit[17*17],ans[18];
signed main()
{
	cin >> n >> m;
	bit[0] = 1;
	for(int i=1;i<=m;i++)
	{
		bit[i] = bit[i-1]*2%mod;
		cin >> a[i] >> b[i];
		a[i]--; b[i]--;
	}
	for(int i=0;i<(1<<n);i++)//计算每个点集内部的边数 
	{
		for(int j=1;j<=m;j++)
			if( ((i>>a[j])&1) && ((i>>b[j])&1) )	
				g[i]++;
	}
	for(int i=0;i<(1<<n);i++)
	{
		int x = 0;
		for(int j=0;j<n;j++)
			if( (i>>j)&1 ) { x = j; break; }
		f[i] = bit[g[i]];
		for(int j=(i-1)&i;j;j=(j-1)&i )
		{
			if( ((j>>x)&1)==0 )	continue;
			f[i] = ( f[i]-f[j]*bit[g[i-j]]%mod )%mod;
		}
	}
	for(int i=0;i<(1<<n);i++)
	{
		if( (i&1)==0 )	continue;
		int temp = f[i]*bit[g[(1<<n)-1-i]]%mod;
		for(int j=0;j<n;j++)
		{
			if( ((i>>j)&1)==0 )	continue;
			ans[j] = ( ans[j]+temp )%mod;
		}
	}
	for(int i=1;i<n;i++)	cout << ( ans[i]%mod + mod )%mod << endl;
	return 0;
}

以上是关于AtCoder Beginner Contest 213G - Connectivity 2(状压dp神仙题)的主要内容,如果未能解决你的问题,请参考以下文章

AtCoder Beginner Contest 234

AtCoder Beginner Contest 115 题解

AtCoder Beginner Contest 154 题解

AtCoder Beginner Contest 103

AtCoder Beginner Contest 228

AtCoder Beginner Contest 242