ATR105F Lights Out on Connected Graph 学习笔记
ATR105F Lights Out on Connected Graph 学习笔记
题意简述
给定一个 \(n\) 点 \(m\) 边的简单无向图 \(G\)。问 \(G\) 有多少个支撑子图为连通的二分图。
定义:若 \(H\subseteq G\) 满足 \(V_H=V_G\),则称 \(H\) 为 \(G\) 的支撑子图。
\(n\le 17\)。
做法解析
本题有两个约束条件:“连通”和“二分图”。“连通”好处理(原理详见 \(\texttt{ATB213G}\) 学习笔记),“二分图”怎么约束出来?
设 \(G_S\) 为只考虑点集 \(S\) 时二分支撑子图(无论连通与否)的个数,\(F_S\) 为只考虑点集 \(S\) 时强连通二分支撑子图的个数。
实际上这是简单的:一个二分图的点集必然可以被黑白染色成一个黑点集和一个白点集,我们就去枚举所有把 \(S\) 分成两个点集的方案。具体来说,我们枚举 \(S\) 的黑点点集 \(T\),即有:\(G_S=\sum_{T\subset S}2^{\text{ecnt}_{T\leftrightarrow S-T}}\)。可以看到,贡献全部是以“二分图的形式”做出来的,也就是说我们在考虑到了 \(T\leftrightarrow S-T\) 的边时,也默认要求了 \(S\) 和 \(T\) 内部的边全部删掉。
然后这题就做完了。注意最后答案要除以二,因为黑白互换本质上是一种方案。
代码实现
无子集卷积优化。
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
using namespace omodint;
using mint=M998;
const int MaxN=17,MaxNs=3e2,MaxNa=1<<17;
int N,M,alf,Gr[MaxN],X,Y,lg2[MaxNa],ecnt[MaxNa];
void addudge(int u,int v){Gr[u]|=(1<<v),Gr[v]|=(1<<u);}
int lowbit(int x){return x&(-x);}
mint pw2[MaxNs],F[MaxNa],G[MaxNa];
int main(){
readi(N),readi(M),alf=(1<<N)-1;
for(int i=2;i<=alf;i<<=1)lg2[i]=lg2[i/2]+1;
pw2[0]=1;for(int i=1;i<=M;i++)pw2[i]=pw2[i-1]*2;
for(int i=1;i<=M;i++)readi(X),readi(Y),addudge(X-1,Y-1);
for(int s=1;s<=alf;s++){
int l=lowbit(s),u=lg2[l],t=s-l;ecnt[s]=ecnt[t];
for(int i=0;i<N;i++)if(t&(1<<i)&&(Gr[u]&(1<<i)))ecnt[s]++;
}
for(int s=0;s<=alf;s++){
for(int t=s;;t=(t-1)&s){
G[s]+=pw2[ecnt[s]-ecnt[t]-ecnt[s-t]];
if(!t)break;
}
}
for(int s=0;s<=alf;s++){
int l=lowbit(s);F[s]=G[s];
for(int t=(s-1)&s;t;t=(t-1)&s)if(t&l)F[s]-=F[t]*G[s-t];
}
writi(miti(F[alf]/2));
return 0;
}
反思总结
见到无向图连通性状压计数,就正难则反处理连通性问题;看到二分图,想黑白染色!
浙公网安备 33010602011771号