题目大意
求一个有向图中不含有一个强连通分量的子图数目。
题目分析
主旋律弱化版。
用$f[S]$表示$S$集合中不含环的子图数目。
枚举$S$的子集$T$,使得$T$作为DAG的汇点不连出任何边,$S-T$可以向$T$随意连边。
在转移的时候顺便统计跨越集合的边的数目。
这样转移可能会重,按照$T$集合大小容斥一下即可。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| #include<algorithm> #include<iostream> #include<iomanip> #include<cstring> #include<cstdlib> #include<climits> #include<vector> #include<cstdio> #include<cmath> #include<queue> using namespace std;
typedef long long LL;
inline const int Get_Int() { int num=0,bj=1; char x=getchar(); while(x<'0'||x>'9') { if(x=='-')bj=-1; x=getchar(); } while(x>='0'&&x<='9') { num=num*10+x-'0'; x=getchar(); } return num*bj; }
#define lowbit(x) ((x)&(-(x)))
const int maxs=(1<<17)+5; const LL mod=1e9+7;
int n,m; LL Pow[maxs],In[maxs],Out[maxs],bitcnt[maxs],f[maxs],p[maxs];
int main() { n=Get_Int(); m=Get_Int(); for(int i=1; i<=m; i++) { int x=1<<(Get_Int()-1),y=1<<(Get_Int()-1); Out[x]|=y; In[y]|=x; } Pow[0]=1; for(int i=1; i<=n*n; i++)Pow[i]=(Pow[i-1]<<1)%mod; bitcnt[0]=0; for(int i=1; i<(1<<n); i++)bitcnt[i]=bitcnt[i^lowbit(i)]+1; f[0]=1; for(int S=1; S<(1<<n); S++) for(int T=S; T; T=(T-1)&S) { if(T!=S) { int u=lowbit(S^T); p[T]=p[T^u]+bitcnt[Out[u]&T]-bitcnt[In[u]&(S^T)]; } else p[T]=0; if(bitcnt[T]&1)f[S]=(f[S]+f[S^T]*Pow[p[T]]%mod)%mod; else f[S]=(f[S]-f[S^T]*Pow[p[T]]%mod+mod)%mod; } printf("%lld\n",f[(1<<n)-1]); return 0; }
|