bzoj4596 [Shoi2016]黑暗前的幻想乡

如果要用矩阵树的话是无法限制公司个数的,发现数据范围十分小,于是考虑容斥,最后答案就等于$n-1$个公司的方案数-$n-2$个公司的方案数+$n-3$个公司的方案数$...$,然后跑矩阵树就好了。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<vector>
 7 #define N 20
 8 #define pb push_back
 9 #define mp make_pair
10 #define mod 1000000007
11 #define int long long
12 using namespace std;
13 int a[N][N],n;
14 int gauss(){
15     for(int i=1;i<=n;i++)
16         for(int j=1;j<=n;j++)
17             (a[i][j]+=mod)%=mod;
18     /*for(int i=1;i<=n;i++){
19         for(int j=1;j<=n;j++)
20             printf("%lld ",a[i][j]);
21         puts("");
22     }puts("");*/
23     int ans=1;
24     for(int k=1;k<n;k++){
25         for(int i=k+1;i<n;i++){
26             while(a[i][k]){
27                 int t=a[k][k]/a[i][k];
28                 for(int j=k;j<n;j++){
29                     a[k][j]=(a[k][j]-t*a[i][j]%mod+mod)%mod;
30                     swap(a[k][j],a[i][j]);
31                 }
32                 ans=(-ans+mod)%mod;
33             }
34         }
35         ans=(ans*a[k][k])%mod;
36     }
37     //printf("%lld\n",ans);
38     return ans;
39 }
40 void add(int x,int y){
41     a[x][x]++;a[y][y]++;
42     a[x][y]--;a[y][x]--;
43 }
44 vector<pair<int,int> >v[N];
45 int bit[20];
46 int getnum(int x){
47     int cnt=0;
48     while(x){cnt++;x^=x&-x;}
49     return cnt;
50 }
51 signed main(){
52     bit[0]=1;
53     for(int i=1;i<=17;i++)bit[i]=bit[i-1]<<1;
54     scanf("%lld",&n);
55     for(int i=1,num;i<n;i++){
56         scanf("%lld",&num);
57         for(int j=1,x,y;j<=num;j++){
58             scanf("%lld%lld",&x,&y);
59             v[i].pb(mp(x,y));
60         }
61     }
62     int tot=0;
63     for(int i=0;i<bit[n-1];i++){
64         memset(a,0,sizeof a);
65         for(int j=1;j<=n;j++)if(i&bit[j-1]){
66             for(int k=0,x,y;k<v[j].size();k++){
67                 x=v[j][k].first,y=v[j][k].second;
68                 add(x,y);
69             }
70         }
71         int now=gauss();
72         if((getnum(i)&1)^((n-1)&1))tot=(tot-now+mod)%mod;
73         else tot=(tot+now)%mod;
74     }
75     printf("%lld\n",tot);
76     return 0;
77 }
View Code

 

posted @ 2018-01-03 21:52  Ren_Ivan  阅读(177)  评论(0编辑  收藏  举报