http://acm.hdu.edu.cn/showproblem.php?pid=5399
/*
先特判有重复数的情况,如果有就输出-1
如果全是数字那么就判是否符合条件
剩下的就是m!的(cout-1)次
*/
/************************************************
* Author :Powatr
* Created Time :2015-8-18 18:40:18
* File Name :1004.cpp
************************************************/
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <cstdlib>
#include <ctime>
using namespace std;
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
typedef long long ll;
const int MAXN = 1e2 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int b[MAXN][MAXN];
int a[MAXN][MAXN];
int c[MAXN];
ll fact(int x)
{
ll ans = 1;
for(int i = 1; i <= x; i++)
ans = ans * i % MOD;
return ans;
}
int main(){
int n, m;
while(~scanf("%d%d", &m, &n)){
int cout = 0;
for(int i = 1; i <= n; i++){
scanf("%d", &a[i][1]);
if(a[i][1] == -1){cout++; continue;}
for(int j = 2; j <= m; j++)
scanf("%d", &a[i][j]);
}
int flag = 0;
for(int i = 1; i <= n; i++){
memset(c, 0, sizeof(c));
if(a[i][1] == -1) continue;
for(int j = 1; j <= m; j++){
if(!c[a[i][j]]) c[a[i][j]] = 1;
else flag = 1;
}
}
if(flag == 1){
puts("0");
continue;
}
int p;
flag = 0;
if(cout == 0){
for(int i = 1; i <= m; i++){
p = i;
for(int j = n; j >= 1; j--)
p = a[j][p];
if(p!=i) flag = 1;
}
if(flag == 1){
puts("0");
continue;
}
// for(int i = 1; i <= m; i++){
// printf("%d ", b[n][i]);}
else {
puts("1");
continue;
}
}
ll ans = 1;
ll ret = fact(m);
for(int i = 1; i < cout; i++){
ans = ans * ret % MOD;
}
printf("%I64d\n", ans);
}
return 0;
}