HDU 5399(简单数学)

来源:互联网 发布:联通网络信号怎么样 编辑:程序博客网 时间:2024/05/01 09:36

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



0 0