[ABC213G] Connectivity 2 题解

好好好。


我们设当前处理 \(i\) 的答案,那么最后的图就可以分成两个部分:\(1\) 所在的联通块和其他,根据乘法原理,答案就是它们二者方案的乘积。

\(f_s\) 表示集合 \(s\) 中所有点联通时图的情况数,\(g_s\) 表示集合 \(s\) 中所有点不一定联通时图的情况数,则有:

\[ans_i=\sum\limits_{\{1,i\}\in s}f_s\times g_{s'} \]

其中 \(s'\) 表示 \(s\) 相对于 \(\{1,2,\dots,n\}\) 这个集合的补集。预处理 \(f_s,g_s\) 的情况下,该部分时间复杂度为 \(O(n2^n)\)

那么现在就要求 \(f_s\)\(g_s\) 了。

\(g_s\) 好说,设 \(dis_{i,j}\) 表示 \(i,j\) 间有没有边,则:

\[g_s=2^{\sum\limits_{i\ \in\ s}\sum\limits_{j\ \in\ s}dis_{i,j}} \]

时间复杂度 \(O(n^22^n)\)

考虑 \(f_s\)。我们暴力出奇迹,强制设一个点 \(v\in s\),将原图划分成两张图,一张有 \(v\),必须连通;一张没 \(v\),不要求连通。这种情况下,我们已经构造出了所有的不连通图情况,那么用 \(g_s\) 减去它,就是 \(f_s\) 的值,即:

\[f_s=g_s-\sum\limits_{t\subsetneq s} f_t\times g_{t'} \]

由于要枚举子集,所以时间复杂度 \(O(3^n)\)

总体时间复杂度 \(O(3^n+n^22^n)\)

#include<bits/stdc++.h>
using namespace std;
const int N=20,M=1<<17;
const int p=998244353;
int n,dis[N][N],f[M];
int m,g[M],tw[N*N];
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m,g[0]=1,tw[0]=1;
	for(int i=1,u,v;i<=m;i++)
		cin>>u>>v,dis[u][v]=1,tw[i]=tw[i-1]*2%p;
	for(int s=1,cnt=0;s<(1<<n);s++,cnt=0){
		for(int i=1;i<n;i++)
			if((s>>(i-1))&1)
				for(int j=n;j>i;j--)
					cnt+=((s>>(j-1))&1)*dis[i][j];
		f[s]=g[s]=tw[cnt];int v=log2(s)+1;
		for(int t=(s&(s-1));t;t=((t-1)&s))
			if((1<<(v-1))&t) f[s]=(f[s]-1ll*f[t]*g[s^t]%p+p)%p;
	}for(int i=2,sum=0;i<=n;i++,sum=0){
		for(int s=1;s<(1<<n);s+=2) if((s>>(i-1))&1)
			sum=(sum+1ll*f[s]*g[((1<<n)-1)^s]%p)%p;
		cout<<sum<<"\n";
	}return 0;
} 
posted @ 2024-10-14 21:41  长安一片月_22  阅读(3)  评论(0编辑  收藏  举报