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

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 }

 

posted @ 2017-12-31 19:42  wfj_2048  阅读(317)  评论(0编辑  收藏  举报