本题目的意思是给出m个 (f1 , f2, ... fm) 置换,一些置换丢失,让求有多少种组合,可以使得 f1( f2(... fm(i))) =i (1<=i<=n) 对多有的i都成立;
这样问题可以转换为若任意确定一些丢失的置换,而保留一个丢失的置换fi, 有 X*fi*Y=I; fi =(X的逆)*(Y的逆)所以,有唯一解,所以个数为记-1的个数为cnt
那么结果(n!)^(cnt-1),本题目有特殊情况要注意.
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<string>
#include<vector>
#include <iostream>
#include<assert.h>
#define pb push_back
#define rep1(i,j,k) for(int i=(j);i<=(int)k;i++)
#define per1(i,j,k) for(int i=(j);i>=(int)k;i--)
#define lowbit(x) ((x)&(-(x)))
#define fi first
#define se second
#define pii pair<int,int>
#define VI vector<int>
using namespace std;
typedef long long ll;
const int N = 110;
const int mod = 1e9+7;
int n,m,f[N][N],cnt;
void read(){
cnt = 0;
rep1(i,1,m){
scanf("%d",&f[i][1]);
if(f[i][1]==-1){cnt++; continue;}
rep1(j,2,n) scanf("%d",&f[i][j]);
}
}
void solve(){
for(int i=1;i<=m;i++){
int vis[1006]={0};
if(f[i][1]==-1) continue;
rep1(j,1,n) { if(++vis[f[i][j]] > 1) {printf("0\n"); return;} }
}
if(cnt == 0){
int ok=1;
rep1(j,1,n){
int now = j;
per1(i,m,1) now=f[i][now];
if(now != j) { ok =0; break; }
}
printf("%d\n",ok);
return ;
}
ll ji=1;
rep1(i,2,n) ji=ji*i%mod;
ll res=1;
rep1(i,1,cnt-1) res=res*ji%mod;
printf("%d\n",(int)res);
}
int main()
{
while(scanf("%d %d",&n,&m)==2){
read();
solve();
}
return 0;
}