[atARC105F]Lights Out on Connected Graph

记$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 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/13802165.html