正着作很差作,因而咱們考慮反着來,如何計算一個點集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 }