[ARC105] F - Lights Out on Connected Graph
题面
题目描述
无向图二分连通生成子图计数。
数据范围
-
\(1\leq n\leq 17\)。
-
\(1\leq m \leq \frac{n(n-1)}{2}\)。
题解
首先先对二分生成子图计数(不要求连通),记 \(f_{S}\) 表示 \(S\) 点集中可能的生成子图个数,\(E(S,T)\) 表示点集 \(S\) 与点集 \(T\) 之间的边数,通过枚举黑/白点集有转移式 \(\displaystyle f_S=\sum_{T\subseteq S} 2^{E(S/T,T)}f_T\),而 \(E(S/T,T)=E(S,S)-E(T,T)-E(S/T,S/T)\),可以预处理。注意此时对于每个二分图 \(G\) 都重复记了 \(2^{\operatorname{comp}(G)}\) 次。
然后现在要把不连通的斥掉。记 \(g_{S}\) 表示 \(S\) 点集中联通的生成子图个数,枚举 \(S\) 中最小值所在的连通块并减去,有转移式 \(\displaystyle g_S=f_S-\sum_{T\subset S\wedge \min(S) \in T} g_Tf_{S/T}\)。
于是答案即为 \(\frac 12g_{\{1,2,...,n\}}\),\(\frac 12\) 是因为 \(2^{\operatorname{comp}(G)}=2^1=2\)。
时间复杂度 \(O(3^n)\),瓶颈在于枚举子集。
#include<bits/stdc++.h>
using namespace std;
const int N=17+9;
const int M=17*17+9;
const int S=(1<<17)+9;
const int mod=998244353;
inline void AddAs(int &x,int y){if((x+=y)>=mod) x-=mod;}
inline void SubAs(int &x,int y){if((x-=y)<0) x+=mod;}
inline void MulAs(int &x,int y){x=1ll*x*y%mod;}
inline int Add(int x,int y){if((x+=y)>=mod) x-=mod;return x;}
inline int Sub(int x,int y){if((x-=y)<0) x+=mod;return x;}
inline int Mul(int x,int y){return 1ll*x*y%mod;}
inline int QPow(int x,int y){
int res=1;
while(y){
if(y&1) MulAs(res,x);
MulAs(x,x);
y>>=1;
}
return res;
}
#define Inv(x) QPow(x,mod-2)
int u[M],v[M],n,m;
int cnt[S],f[S],g[S],pw[M];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
#define endl '\n'
cin>>n>>m;
for(int i=1;i<=m;i++) cin>>u[i]>>v[i];
pw[0]=1;for(int i=1;i<=m;i++) pw[i]=Add(pw[i-1],pw[i-1]);
for(int sta=0;sta<(1<<n);sta++){
for(int i=1;i<=m;i++) if((sta>>u[i]-1&1)&&(sta>>v[i]-1&1)) cnt[sta]++;
for(int tta=sta;;tta=sta&tta-1){
AddAs(f[sta],pw[cnt[sta]-cnt[tta]-cnt[sta^tta]]);
if(!tta) break ;
}
}
for(int sta=0;sta<(1<<n);sta++){
g[sta]=f[sta];
for(int tta=sta&sta-1;tta>(sta>>1);tta=sta&tta-1){
SubAs(g[sta],Mul(g[tta],f[sta^tta]));
}
}
cout<<Mul(g[(1<<n)-1],Inv(2))<<endl;
return 0;
}

浙公网安备 33010602011771号