Too Simple
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 449 Accepted Submission(s): 158
Teacher Mai has m functions f1,f2,⋯,fm:{1,2,⋯,n}→{1,2,⋯,n} (that means for all x∈{1,2,⋯,n},f(x)∈{1,2,⋯,n} ). But Rhason only knows some of these functions, and others are unknown.
She wants to know how many different function series f1,f2,⋯,fm there are that for every i(1≤i≤n) , f1(f2(⋯fm(i)))=i . Two function series f1,f2,⋯,fm and g1,g2,⋯,gm are considered different if and only if there exist i(1≤i≤m),j(1≤j≤n) , fi(j)≠gi(j) .
The following are m lines. In i -th line, there is one number −1 or n space-separated numbers.
If there is only one number −1 , the function fi is unknown. Otherwise the j -th number in the i -th line means fi(j) .
3 3 1 2 3 -1 3 2 1
1HintThe order in the function series is determined. What she can do is to assign the values to the unknown functions.
给你m个函数f1,f2,⋯,fm:{1,2,⋯,n}→{1,2,⋯,n}(即所有的x∈{1,2,⋯,n},对应的f(x)∈{1,2,⋯,n}),已知其中一部分函数的函数值,问你有多少种不同的组合使得所有的i(1≤i≤n),满足f1(f2(⋯fm(i)))=i
对于函数集f1,f2,⋯,fm and g1,g2,⋯,gm,当且仅当存在一个i(1≤i≤m),j(1≤j≤n),fi(j)≠gi(j),这样的组合才视为不同。
比如样例,3 3
1 2 3
-1
3 2 1
样例写成函数的形式就是
n=3,m=3(m行,每行n个数)
f1(1)=1,f1(2)=2,f1(3)=3
f2(1)、f2(2)、f2(3)的值均未知
f3(1)=3,f3(2)=2,f3(3)=1
所以要使所有的i(1≤i≤n),满足f1(f2(⋯fm(i)))=i,只有一种组合情况,即f2(1)=3,f2(2)=2,f2(3)=1
解题思路:当某一行的映射不能保证一对一时(换句话说就是多对一),那么一定存在i(1≤i≤n)不满足f1(f2(⋯fm(i)))=i,此时结果为0。除了这种特殊情况,题的解跟-1的个数有关,当-1的个数是0时,结果未必是0,,要判断对所有的i是否都满足条件,如果满足,结果是1,否则结果是0。当只有一个-1的时候,因为对应关系都已经确定了,所以只有1种可行解,而当有两个-1时,其中一个函数的值可以根据另一个函数的改变而确定下来,故有n!种解。依此类推,当有k个-1时,解为(n!)^(k-1)(k>0)。
代码如下:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
#include <limits.h>
#define debug "output for debug\n"
#define pi (acos(-1.0))
#define eps (1e-6)
#define inf (1<<28)
#define sqr(x) (x) * (x)
#define mod 1000000007
using namespace std;
typedef long long ll;
typedef unsigned long long ULL;
//
int a[105][105];
//
ll fac[105];
//阶乘:fac[i]=i!%mod
void Factorial()
{
fac[0]=1;
for(int i=1;i<105;i++)
fac[i]=fac[i-1]*i%mod;
}
//判断对所有的i(1≤i≤n)是否满足,f1(f2(⋯fm(i)))=i
int judge(int n,int m)
{
int i,j,k;
//枚举n个数
for(i=1;i<=n;i++)
{
k=i;
//映射m次
for(j=m;j>0;j--)
k=a[j][k];
//判断
if(k!=i)
return 0;
}
return 1;
}
/*
//判断对所有的i(1≤i≤n)是否满足,f1(f2(⋯fm(i)))=i
int judge(int n,int m)
{
int i,j,b[105];
//初始第m行的i值
for(i=1;i<=n;i++)
b[i]=i;
//整行的进行映射
for(i=m;i>0;i--)
{
for(j=1;j<=n;j++)
b[j]=a[i][b[j]];
}
//判断
for(i=1;i<=n;i++)
{
if(b[i]!=i)
return 0;
}
return 1;
}
*/
int main()
{
int i,j,k,n,m,ant,flag;
//标记映射关系一对一
int vis[105];
Factorial();//
while(~scanf("%d%d",&n,&m))
{
memset(a,0,sizeof(a));
ant=0;
flag=0;
for(i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
if(x==-1)
ant++;//记录-1的个数
else
{
memset(vis,0,sizeof(vis));
a[i][1]=x;
//1~n之间的数出现标记为1,否则标记为0
vis[a[i][1]]=1;
for(j=2;j<=n;j++)
{
scanf("%d",&a[i][j]);
//1~n之间的数出现标记为1,否则标记为0
vis[a[i][j]]=1;
}
//判断映射关系是否一对一
if(flag==0)
{
for(j=1;j<=n;j++)
{
if(vis[j]==0)
{
//不符合一对一
flag=1;
break;
}
}
}
}
}
if(flag)
printf("0\n");
else if(ant==0)//
printf("%d\n",judge(n,m));
else//(n!)^(ant-1)
{
long long ans=1;
for(i=1;i<ant;i++)
ans=ans*fac[n]%mod;
printf("%I64d\n",ans);
}
}
return 0;
}