4894: 天赋

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 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

Sample Output

72373

HINT

Source

By 佚名上传

题解:根向儿子,入度矩阵,儿子向根,出度矩阵。

什么意思,第一种,比如u-->v则 v,v++ ,u,v--

另外一直则 u-->v u,u++ v,u--

第二种就是将边反向,然后变成第一种。

有向树中删除的那一行必须是根的那一行。

 #pragma GCC optimize(2)
#pragma G++ optimize(2)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring> #define ll long long
#define N 307
#define mod 1000000007
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-;ch=getchar();}
while(isdigit(ch)){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*f;
} int n;
ll a[N][N];
char ch[N];
ll ans=; int main()
{
n=read();
for (int i=;i<=n;i++)
{
scanf("%s",ch+);
for (int j=;j<=n;j++)
if(ch[j]=='') a[j][j]++,a[i][j]--;
}
for (int i=;i<=n;i++)
{
for (int j=i+;j<=n;j++)
{
int A=a[i][i],B=a[j][i];
while(B)
{
int t=A/B;A%=B;swap(A,B);
for(int k=i;k<=n;k++)(a[i][k]=a[i][k]-t*a[j][k]%mod+mod)%=mod;
for(int k=i;k<=n;k++)swap(a[i][k],a[j][k]);
ans=-ans;
}
}
if(!a[i][i])cout<<i<<endl;
(ans*=a[i][i])%=mod;
if(!a[i][i])break;
}
printf("%lld\n",(ans%mod+mod)%mod);
}
05-11 16:16