本题目的意思是给出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; }