Cry_For_theMoon  

传送门

F 是后缀数组,H 是分治 FFT,你管这叫 ABC?

题意:

给定 \(n\)\(m\) 边无向图 \(G\),无自环,无重边。对于每个 \(k \in [2,n]\),试求 \(G\) 的子图个数,满足点 \(1\) 与点 \(k\) 是连通的。

Data range:\(n \le 17,m \le \frac{n(n-1)}{2}\)

分析:

一个月前教练讲过一道同类型同做法,比这道题还难不少的题:Topcoder15279-Spanning Subgraphs

可惜我当时摸鱼没有补,导致 ABC 赛场上切完 E 罚坐 70 min。

容易想到状压求解。有一个显然的事实是,不能通过枚举边来转移。比如说边依次为 \((2,3),(1,2)\),就会假掉。因为你记录的肯定是和 \(1\) 连通的点,不然状态会炸掉。而如果通过枚举边来转移,那么如果 \(1-3\) 需要连通,我两条边肯定都得选,但是选第一条边的时候 \(2,3\) 都不与 \(1\) 连通,无法记录到。

所以直接考虑设 \(f(S)\) 为让点集 \(S\) 连通的子图数(\(1 \in S\))。考虑容斥,设 \(g(S)\) 为点集为 \(S\) 的子图数(不要求连通),那么 \(g(S)\) 的计算是容易的:计算所有边的两端点都在 \(S\) 的边数 \(cnt\),则 \(g(S)=2^{cnt}\)。那么有:

\[f(S)=g(S)-\sum_{1\in T\nsubseteq S}f(S)g(S\setminus T) \]

奇怪的是,不管要不要求 \(1 \in T\)(不然会算重),AT上都能AC。我暂且蒙古。

那么这部分的总复杂度就是 \(3^n\) 的。考虑 \(g\) 的计算,显然是 \(2^nm\) 的,所以总复杂度为:\(O(3^n+2^nm)\)

#include<bits/stdc++.h>
#define rep(i,a,b) for(ll i=(a);i<=(b);i++)
#define per(i,a,b) for(ll i=(a);i>=(b);i--)
#define op(x) ((x&1)?x+1:x-1)
#define odd(x) (x&1)
#define even(x) (!odd(x))
#define lc(x) (x<<1)
#define rc(x) (lc(x)|1)
#define lowbit(x) (x&-x)
#define Max(a,b) (a>b?a:b)
#define Min(a,b) (a<b?a:b)
#define next Cry_For_theMoon
#define il inline
#define pb(x) push_back(x)
#define is(x) insert(x)
#define sit set<int>::iterator
#define mapit map<int,int>::iterator
#define pi pair<int,int>
#define ppi pair<int,pi>
#define pp pair<pi,pi>
#define fr first
#define se second
#define vit vector<int>::iterator
#define mp(x,y) make_pair(x,y)
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef double db;
using namespace std;
const int MAXN=18,mod=998244353;
int n,m,edge[MAXN][MAXN];
ll g[(1<<18)],f[(1<<18)];
int main(){
	cin>>n>>m;
	rep(i,1,m){
		ll u,v;cin>>u>>v;
		edge[u][v]=edge[v][u]=1;
	}
	rep(i,0,(1<<n)-1){
		g[i]=1;
		rep(u,1,n){
			rep(v,u+1,n){if(!edge[u][v])continue;
				if((i&(1<<(u-1))) && (i&(1<<(v-1)))){
					g[i]=g[i]*2%mod;
				}
			} 
		} 
	}
	rep(i,1,(1<<n)-1){
		if(!(i&1))continue;
		f[i]=g[i];
		for(ll j=i;j;j=(j-1)&i){
			if(j==i)continue;
			if(!(j&1))continue;
			f[i]=(f[i]-f[j]*g[i^j]%mod+mod)%mod;
		}
	}
	rep(k,2,n){
		ll ans=0;
		rep(i,1,(1<<n)-1){
			if(!(i&1) || !(i&(1<<(k-1))))continue;
			ans=(ans+f[i]*g[((1<<n)-1)^i]%mod)%mod;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

posted on 2021-08-09 10:33  Cry_For_theMoon  阅读(133)  评论(0编辑  收藏  举报