bzoj4894 天赋
Description
小明有许多潜在的天赋,他希望学习这些天赋来变得更强。正如许多游戏中一样,小明也有n种潜在的天赋,但有一些天赋必须是要有前置天赋才能够学习得到的。也就是说,有一些天赋必须是要在学习了另一个天赋的条件下才能学习的。比如,要想学会"开炮",必须先学会"开枪"。一项天赋可能有多个前置天赋,但只需习得其中一个就可以学习这一项天赋。上帝不想为难小明,于是小明天生就已经习得了1号天赋-----"打架"。于是小明想知道学习完这n种天赋的方案数,答案对1,000,000,007取模。
Input
第一行一个整数n。
接下来是一个n*n的01矩阵,第i行第j列为1表示习得天赋j的一个前置天赋为i。
数据保证第一列和主对角线全为0。
n<=300
Output
第一行一个整数,问题所求的方案数。
Sample Input
8
01111111
00101001
01010111
01001111
01110101
01110011
01111100
01110110
01111111
00101001
01010111
01001111
01110101
01110011
01111100
01110110
Sample Output
72373
正解:矩阵树定理+高斯消元。
有向图树形图计数问题。。
假设边的方向是从根往叶子,那么需要消元的矩阵变成入度矩阵-邻接矩阵,同时必须去掉根的那一行和那一列再求行列式。
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 #define rhl (1000000007) 6 7 using namespace std; 8 9 int d[305][305],g[305][305],n,ans; 10 11 il int gi(){ 12 RG int x=0,q=1; RG char ch=getchar(); 13 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 14 if (ch=='-') q=-1,ch=getchar(); 15 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 16 return q*x; 17 } 18 19 il char gc(){ 20 RG char ch=getchar(); 21 while (ch!='0' && ch!='1') ch=getchar(); 22 return ch; 23 } 24 25 il int qpow(RG int a,RG int b){ 26 RG int ans=1; 27 while (b){ 28 if (b&1) ans=1LL*ans*a%rhl; 29 a=1LL*a*a%rhl,b>>=1; 30 } 31 return ans; 32 } 33 34 il void gauss(){ 35 for (RG int i=2,id;i<=n;++i){ 36 for (id=i;id<=n;++id) if (d[id][i]!=0) break; 37 for (RG int j=2;j<=n;++j) swap(d[i][j],d[id][j]); 38 RG int inv=qpow(d[i][i],rhl-2); 39 for (RG int j=i+1;j<=n;++j){ 40 RG int tmp=d[j][i]; 41 for (RG int k=i;k<=n;++k){ 42 d[j][k]+=rhl-1LL*d[i][k]*inv%rhl*tmp%rhl; 43 if (d[j][k]>=rhl) d[j][k]-=rhl; 44 } 45 } 46 ans=1LL*ans*d[i][i]%rhl; 47 } 48 return; 49 } 50 51 int main(){ 52 #ifndef ONLINE_JUDGE 53 freopen("talent.in","r",stdin); 54 freopen("talent.out","w",stdout); 55 #endif 56 n=gi(),ans=1; 57 for (RG int i=1;i<=n;++i) 58 for (RG int j=1;j<=n;++j) g[i][j]=gc()=='1'; 59 for (RG int i=1,tmp=0;i<=n;++i,tmp=0){ 60 for (RG int j=1;j<=n;++j) tmp+=g[j][i]; 61 d[i][i]=tmp; 62 } 63 for (RG int i=1;i<=n;++i) 64 for (RG int j=1;j<=n;++j) 65 (d[i][j]+=rhl-g[i][j])%=rhl; 66 gauss(),cout<<ans; return 0; 67 }