记$G[S]$表示图$G$在点集$S$上的导出子图,即$G[S]=(S,{(x,y)|x,yin S且(x,y)in E})$
定义$g(S)$为所有$E'$(满足$E'subseteq G[S].E$)的图$G'=(S,E')$的染色方式之和,考虑枚举其中一种颜色的点集,则有$g(S)=sum_{Tsubseteq S}2^{|{(x,y)|(x,y)in E且xin T且yin C_{S}T}|}$(这些边可以选或不选)
考虑计算$|{(x,y)|(x,y)in G[S].E且xin T且yin C_{S}T}|$,可以看作$S$中边数-$T$中边数-$C_{S}T$中边数,$o(2^{n}m)$预处理出$|G[S].E|$,那么即$|G[S].E|-|G[T].E|-|G[C_{S}T].E|$
定义$f(S)$为有多少$E'$使得$E'subseteq G[S].E$且$G'=(S,E')$为好图,那么$f(V)$即为答案
$f(S)$的计算略微比较复杂,定义$g'(S)$为所有不连通的$G'=(S,E')$(参考$g(S)$定义)的染色方式之和,容易发现有$f(S)=frac{g(S)-g'(S)}{2}$(联通二分图有2种染色方式)
对于$g'(S)$,枚举$S$的某个$k$所属连通块,那么即有$g'(S)=sum_{kin T,Tsubset S}f(T)g(C_{S}T)$($k$为$S$中任意一个元素,注意这里$T e S$)
上面的转移涉及到一个枚举子集的技巧,因此时间复杂度$o(3^{n}+2^{n}m)$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 4 #define M 1005 5 #define mod 998244353 6 int n,m,x,y,mi[M],e[M],se[N],g[N],f[N]; 7 int main(){ 8 scanf("%d%d",&n,&m); 9 mi[0]=1; 10 for(int i=1;i<=m;i++){ 11 scanf("%d%d",&x,&y); 12 e[i]=((1<<x-1)|(1<<y-1)); 13 mi[i]=mi[i-1]*2%mod; 14 } 15 for(int i=0;i<(1<<n);i++) 16 for(int j=1;j<=m;j++)se[i]+=((i&e[j])==e[j]); 17 for(int i=0;i<(1<<n);i++){ 18 g[i]=1; 19 for(int j=i;j;j=((j-1)&i))g[i]=(g[i]+mi[se[i]-se[j]-se[i^j]])%mod; 20 } 21 for(int i=0;i<(1<<n);i++){ 22 f[i]=g[i]; 23 int k=i-(i&(i-1)); 24 for(int j=i-k;j;j=((j-1)&i)) 25 if (j&k)f[i]=(f[i]+mod-1LL*f[j]*g[i^j]%mod)%mod; 26 } 27 printf("%lld",f[(1<<n)-1]*(mod+1LL)/2%mod); 28 }