4894: 天赋
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 104 Solved: 80
[Submit][Status][Discuss]
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
HINT
Source
题解:根向儿子,入度矩阵,儿子向根,出度矩阵。
什么意思,第一种,比如u-->v则 v,v++ ,u,v--
另外一直则 u-->v u,u++ v,u--
第二种就是将边反向,然后变成第一种。
有向树中删除的那一行必须是根的那一行。
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 307 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 ll a[N][N]; 23 char ch[N]; 24 ll ans=1; 25 26 int main() 27 { 28 n=read(); 29 for (int i=1;i<=n;i++) 30 { 31 scanf("%s",ch+1); 32 for (int j=1;j<=n;j++) 33 if(ch[j]=='1') a[j][j]++,a[i][j]--; 34 } 35 for (int i=2;i<=n;i++) 36 { 37 for (int j=i+1;j<=n;j++) 38 { 39 int A=a[i][i],B=a[j][i]; 40 while(B) 41 { 42 int t=A/B;A%=B;swap(A,B); 43 for(int k=i;k<=n;k++)(a[i][k]=a[i][k]-t*a[j][k]%mod+mod)%=mod; 44 for(int k=i;k<=n;k++)swap(a[i][k],a[j][k]); 45 ans=-ans; 46 } 47 } 48 if(!a[i][i])cout<<i<<endl; 49 (ans*=a[i][i])%=mod; 50 if(!a[i][i])break; 51 } 52 printf("%lld ",(ans%mod+mod)%mod); 53 }