bzoj3812&uoj37 主旋律

正着作很差作,因而咱們考慮反着來,如何計算一個點集s的答案呢,必定是全部的方案減去不合法的方案,不合法的方案必定是縮完點後是一個DAG,那麼就必定有度數爲0的scc,因而咱們枚舉s的子集,就是說這些點構成的scc的度數爲0,這裏咱們就須要容斥了,容斥的目的是算出s集組成不合法的DAG的方案數,由於咱們沒有辦法肯定這裏有幾個scc。因而咱們提早處理出g[s]表示這裏面的每種不一樣scc的方案的貢獻是$-1^{num-1}$,而後它們和其他的點之間隨便連邊,其他的點之間也隨便連邊,而後g數組咱們是枚舉任意一個點,而後枚舉它所在的scc,而後在經過f數組轉移,f就是總方案減去全部子集度數爲0時的方案。數組

妙妙啊。ide

 1 #include <cstdio>
 2 #define N 16
 3 #define mod 1000000007
 4 using namespace std;
 5 int n,m,to[1<<N],cnt[1<<N],bin[N*N],e[1<<N];
 6 int f[1<<N],g[1<<N];
 7 int calc(int S,int T){
 8     int ans=0;
 9     for(;S;S-=S&-S)
10         ans+=cnt[to[S&-S]&T];
11     return ans;
12 }
13 int main(){
14     scanf("%d%d",&n,&m);
15     bin[0]=1;
16     for(int i=1;i<=m;i++)
17         bin[i]=bin[i-1]*2%mod;
18     for(int i=1,u,v;i<=m;i++){
19         scanf("%d%d",&u,&v);
20         to[1<<u-1]|=1<<v-1;
21     }
22     for(int i=1;i<bin[n];i++)cnt[i]=cnt[i>>1]+(i&1);
23     for(int i=1;i<bin[n];i++)e[i]=calc(i,i);
24     for(int i=1;i<bin[n];i++){
25         int k=i&-i,s=i^k;
26         for(int j=(s-1)&s;j;j=(j-1)&s)
27             g[i]=(g[i]-1ll*g[i^j^k]*f[j|k]%mod+mod)%mod;
28         if(i^k)g[i]=(g[i]-g[i^k]+mod)%mod;
29         f[i]=bin[e[i]];
30         for(int j=i;j;j=(j-1)&i)
31             f[i]=(f[i]-1ll*g[j]*bin[e[i^j]+calc(j,i^j)]%mod+mod)%mod;
32         (g[i]+=f[i])%=mod;
33     }
34     printf("%d\n",f[bin[n]-1]);
35     return 0;
36 }
View Code
相關文章
相關標籤/搜索