1. 程式人生 > 實用技巧 >[atARC105F]Lights Out on Connected Graph

[atARC105F]Lights Out on Connected Graph

記$G[S]$表示圖$G$在點集$S$上的匯出子圖,即$G[S]=(S,{(x,y)|x,y\in S且(x,y)\in E})$

定義$g(S)$為所有$E'$(滿足$E'\subseteq G[S].E$)的圖$G'=(S,E')$的染色方式之和,考慮列舉其中一種顏色的點集,則有$g(S)=\sum_{T\subseteq S}2^{|\{(x,y)|(x,y)\in E且x\in T且y\in C_{S}T\}|}$(這些邊可以選或不選)

考慮計算$|\{(x,y)|(x,y)\in G[S].E且x\in T且y\in 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_{k\in T,T\subset S}f(T)g(C_{S}T)$($k$為$S$中任意一個元素,注意這裡$T\ne 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