HDU 5399(简单数学)

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



你可能感兴趣的:(HDU 5399(简单数学))