Description
Input
Output
Sample Input
2 3 2 4 2
5 2 1 3 1 3 2 4 1 4 3
4 2 1 3 2 4 1 4 2
Sample Output
题解:可以采用2^n的容斥原理,暴力枚举每个公司选或不选,然后将这些公司的边放到一起,用矩阵树定理求出方案数。那么答案就是:
可能全选的-至少不选1个的+至少不选2个的-。。。
#include <cstdio> #include <cstring> #include <iostream> #include <vector> using namespace std; typedef long long ll; const ll P=1000000007; ll ans; int n,S; vector<int> pa[20],pb[20]; ll v[20][20]; inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar(); return ret*f; } ll calc() { int i,j,k; ll A,B,tmp,temp,ret=1; memset(v,0,sizeof(v)); for(i=1;i<n;i++) if((S>>(i-1))&1) for(j=0;j<(int)pa[i].size();j++) A=pa[i][j],B=pb[i][j],v[A][B]--,v[B][A]--,v[A][A]++,v[B][B]++; for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(v[i][j]<0) v[i][j]+=P; for(i=1;i<n;i++) { for(j=i+1;j<n;j++) { A=v[i][i],B=v[j][i]; while(B) { tmp=A/B,temp=A,A=B,B=temp%B; for(ret=P-ret,k=i;k<n;k++) v[i][k]=(v[i][k]-tmp*v[j][k]%P+P)%P,swap(v[i][k],v[j][k]); } } ret=ret*v[i][i]%P; } return ret; } void dfs(int x,int f) { if(x==n) { ans=(ans+f*calc())%P; return ; } S|=1<<(x-1),dfs(x+1,f); S^=1<<(x-1),dfs(x+1,-f); } int main() { n=rd(); int i,a; for(i=1;i<n;i++) { a=rd(); while(a--) pa[i].push_back(rd()),pb[i].push_back(rd()); } dfs(1,1); ans=(ans+P)%P; printf("%lld",ans); return 0; }
| 欢迎来原网站坐坐! >原文链接<