bzoj 4596 [Shoi2016]黑暗前的幻想乡 矩阵树定理+容斥
4596: [Shoi2016]黑暗前的幻想乡
Time Limit: 20 Sec Memory Limit: 256 MB
Submit: 559 Solved: 325
[Submit][Status][Discuss]
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
HINT
Source
容斥一下让哪几个公司来修就可以了,然后每次矩阵树定理求一下方案树就可以了。
这里是直接高斯消元的,没有辗转相除的形式,但是好像矩阵树是保证还是桌面回事,不需要的。
- 1 #pragma GCC optimize(2)
- 2 #pragma G++ optimize(2)
- 3 #include<iostream>
- 4 #include<algorithm>
- 5 #include<cmath>
- 6 #include<cstdio>
- 7 #include<cstring>
- 8
- 9 #define ll long long
- 10 #define N 22
- 11 #define mod 1000000007
- 12 using namespace std;
- 13 inline int read()
- 14 {
- 15 int x=0,f=1;char ch=getchar();
- 16 while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
- 17 while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
- 18 return x*f;
- 19 }
- 20
- 21 int n;
- 22 int a[N][N],f[N][N],ans;
- 23 int cnt,hed[N];
- 24 struct Node
- 25 {
- 26 int x,y,nxt;
- 27 }e[10007];
- 28
- 29 void add(int u,int x,int y)
- 30 {
- 31 e[++cnt].x=x;
- 32 e[cnt].y=y;
- 33 e[cnt].nxt=hed[u];
- 34 hed[u]=cnt;
- 35 }
- 36 int cal(int num)//矩阵树定理是每个点的度,若x-y有边则x,y -1,y,x -1然后消去一行,下三角消元
- 37 {
- 38 //这里好处是num为n-1了,已经减去一行了。
- 39 for (int i=1;i<=num;i++)
- 40 for (int j=1;j<=num;j++)
- 41 a[i][j]=f[i][j];
- 42 int ans=1;
- 43 for (int i=1;i<=num;i++)
- 44 {
- 45 for (int j=i+1;j<=n;j++)
- 46 while(a[j][i])
- 47 {
- 48 int t=a[i][i]/a[j][i];
- 49 for (int k=i;k<=n;k++)a[i][k]=(a[i][k]-(ll)a[j][k]*t%mod)%mod;
- 50 for (int k=i;k<=n;k++)swap(a[i][k],a[j][k]);
- 51 ans=-ans;//ans去反是因为斜对角线上负数的个数
- 52 }
- 53 if(!a[i][i])return 0;
- 54 ans=(ll)ans*a[i][i]%mod;
- 55 }
- 56 return ans;
- 57 }
- 58 void dfs(int x,int y)
- 59 {
- 60 if (x==n)//就n-1个人
- 61 {
- 62 (ans+=y*cal(n-1))%=mod;
- 63 return;
- 64 }
- 65 dfs(x+1,y);
- 66
- 67 for (int i=hed[x];i!=-1;i=e[i].nxt)
- 68 {
- 69 int u=e[i].x,v=e[i].y;
- 70 f[u][u]--,f[v][v]--,f[u][v]++,f[v][u]++;
- 71 }
- 72 dfs(x+1,-y);
- 73 for (int i=hed[x];i!=-1;i=e[i].nxt)
- 74 {
- 75 int u=e[i].x,v=e[i].y;
- 76 f[u][u]++,f[v][v]++,f[u][v]--,f[v][u]--;
- 77 }
- 78 }
- 79 int main()
- 80 {
- 81 memset(hed,-1,sizeof(hed));
- 82 n=read();
- 83 for (int i=1;i<n;i++)
- 84 {
- 85 int number=read();
- 86 for (int j=1;j<=number;j++)
- 87 {
- 88 int x=read(),y=read();
- 89 add(i,x,y);
- 90 f[x][x]++,f[y][y]++,f[x][y]--,f[y][x]--;
- 91 }
- 92 }
- 93 dfs(1,1);
- 94 printf("%d\n",(ans%mod+mod)%mod);
- 95 }