UOJ#37. 【清华集训2014】主旋律
題目大意:
傳送門
題解:
神題……Orz。
首先正難則反。
設$f_S$表示選取點集狀態為s時,這部分圖可以構成非強聯通圖的方案數。
設$p_{S,i}$表示點集s縮點后有i個入度為0點的方案數,保證$i<|S|$。
設$e[S,T]$表示從S集合到T集合的邊數。
很顯然有。
好吧,并不顯然……還是來解釋一下……
考慮求$f_S$,我們知道縮點后必然會有一些點環的入度為0,但數量并不確定,我們強制性的讓一部分圖構成一部分縮點后為i個入度為0的子圖。然后將這部分圖隨意連向剩余子圖,至于剩余子圖內部也可以隨便連。但是顯然當$T==S$時,我們需要讓被選擇的圖縮點后至少要有2個入度為0的點。
然后這個東西顯然(這次是真的)是會重的,為了去重,我們使用容斥原理,這樣我們就得到了上面這玩意。
問題是這東西怎么求……
我們設。
值得注意的會發現$g_S$和其他子圖不太一樣(縮點后有至少兩個入度為0的點?)……
我們先想這東西怎么搞……
先假設已經知道$T\neq S$的$g$值。
那么考慮當我們枚舉到$T==S$時,由于我們已經將兩部分圖中連邊的方案容斥完了(因為$T==S$時,T不可能再向$S-T$連邊)。那么還剩下的就是兩部分圖中不連邊的方案還沒有容斥完。(請注意是兩部分)
為了滿足容斥,$g_S$此時應該記錄的是分成若干個聯通塊以后沒有邊的方案數。
這樣的話就會導致一個問題$g_S$對于$f_S$和$f_S+I,I\cap S \neq |I|$的意義是不一樣的。但$S+I$太遙遠了,我們先考慮對于S的意義該怎么算。
我們還是可以枚舉$S$的子集,我們會得到$g_S=-\sum_T g_T * (2^{e[S-T,S-T]}-f_{S-T})$即我們強制一部圖為一個強聯通分量,另外一部分圖我們使其數量任意。為了使其構成我們想要的意義,那么我們強行不讓他們連邊。這樣我們$S$相對與$T$就多了一個強聯通分量,故要乘上$-1$。
但這樣會出現一個問題,就是我們必然會算重。比如$g_T$中是包含縮成1個點的方案的,$S-T$我們又讓它縮成了1個點,這樣我們比如會重復計算。當然出重的不只這些。
那么為了避免出現這種情況,同時枚舉時必然是兩個非空子集。那我們就強制讓一個點劃分到一部分子集里。這樣我們就可以解決這個問題了。
回來考慮$g_S$對$S+I$該怎么算,我們注意到他們之間的區別是當對于$S$時,我們要求分成至少兩個強聯通分量,而$S-T$時則可以只有1個,那么我們直接給$g_S$加上$2^{e[S,S]-f_S}$不就完事了。
真難表述……(辣雞linux沒有仿宋字體,看得好難受
代碼:
1 #include "bits/stdc++.h" 2 3 using namespace std; 4 5 inline int read(){ 6 int s=0,k=1;char ch=getchar(); 7 while (ch<'0'|ch>'9') ch=='-'?k=-1:0,ch=getchar(); 8 while (ch>47&ch<='9') s=s*10+(ch^48),ch=getchar(); 9 return s*k; 10 } 11 12 const int N=20,M=1<<N,mod=1e9+7; 13 14 int n,m,S; 15 int edge[M],num[M],bin[N*N],f[M],g[M],e[M],redge[M],w[M],lgs[M]; 16 17 int main(){ 18 //freopen(".in","r",stdin); 19 //freopen("vio.out","w",stdout); 20 register int i,j,k,res; 21 n=read(),m=read(); 22 for (i=1;i<=m;++i) { 23 j=read(),k=read(); 24 edge[1<<j-1]^=1<<k-1; 25 redge[1<<k-1]^=1<<j-1; 26 } 27 for (i=bin[0]=1;i<=m;++i) j=(bin[i-1]<<1),j<mod?bin[i]=j:bin[i]=j-mod; 28 29 for (S=1<<n,i=1;i^S;++i) num[i]=num[i>>1]+(i&1); 30 for (i=1,lgs[0]=-1;i^S;++i) lgs[i]=lgs[i>>1]+1; 31 for (i=1;i^S;++i) j=bin[lgs[i]],e[i]=e[i^j]+num[redge[j]&(i^j)]+num[edge[j]&(i^j)]; 32 for (i=1;i<S;++i) { 33 k=i&-i,res=i^k; 34 for (j=res&res-1;j;j=j-1&res) { 35 g[i]+=1ll*g[res^j]*(bin[e[j^k]]-f[j^k]+mod)%mod; 36 g[i]<mod?0:g[i]-=mod; 37 } 38 if (num[i]>1) g[i]+=g[res],g[i]<mod?0:g[i]-=mod; 39 g[i]=g[i]?mod-g[i]:0; 40 for (j=res;j;j=j-1&i) { 41 k=bin[lgs[i^j]]; 42 w[i^j]=w[i^j^k]+num[redge[k]&j]-num[edge[k]&(i^j^k)]; 43 f[i]+=1ll*bin[e[i^j]+w[i^j]]*g[j]%mod; 44 f[i]<mod?0:f[i]-=mod; 45 } 46 f[i]+=g[i]; 47 f[i]<mod?0:f[i]-=mod; 48 g[i]+=(bin[e[i]]-f[i]+mod)%mod; 49 g[i]<mod?0:g[i]-=mod; 50 } 51 printf("%d\n",(bin[m]-f[S-1]+mod)%mod); 52 return 0; 53 }?
轉載于:https://www.cnblogs.com/Troywar/p/8879470.html
總結
以上是生活随笔為你收集整理的UOJ#37. 【清华集训2014】主旋律的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: robotframework如何设计we
- 下一篇: chromedriver与chrome版