3 3 1 2 3 -1 3 2 1
1HintThe order in the function series is determined. What she can do is to assign the values to the unknown functions.
思路与官方的一样:
首先要求每个fi是个排列,否则如果某个fi将两个数映射向同一个数,那么最后这两个数得到的值一定相同。
如果还剩一个位置为−1,那么这个排列是唯一确定的,假设X∗fi∗Y=I,那么fi=X−1∗Y−1.
所以假设有c(c≥1)个−1,那么答案为(n!)c−1个可行的方案。
注意特判所有函数都已知的情况。
#include <cstdio> #include <cstring> using namespace std; const long long MOD=1000000007; long long f[101]; int a[101][101]; bool vis[101]; void Init() { f[0]=f[1]=1; for(long long i=2;i<=100;++i) f[i]=(f[i-1]*i)%MOD; } long long quickpow(long long m,long long n) { long long b=1; while(n>0){ if (n&1) b=(b*m)%MOD; n=n>>1; m=(m*m)%MOD; } return b; } int n,m; bool Judge() {//特判所有函数已知的情形 int i,j,x; for(i=1;i<=n;++i) { x=i; for(j=m-1;j>=0;--j) x=a[j][x]; if(x!=i) return false; } return true; } int main() { int i,j,cnt; bool ok; Init(); while(2==scanf("%d%d",&n,&m)) { cnt=0,ok=true; for(i=0;i<m;++i) { scanf("%d",&a[i][1]); if(a[i][1]==-1) ++cnt; else { memset(vis,false,sizeof(vis)); vis[a[i][1]]=true; for(j=2;j<=n;++j) { scanf("%d",&a[i][j]); if(vis[a[i][j]])//刚开始以为是单射函数,结果WA了好久。如果存在非单射函数,则结果为0 ok=false; else vis[a[i][j]]=true; } } } if(cnt==0) printf("%d\n",Judge()?1:0); else printf("%I64d\n",ok?quickpow(f[n],cnt-1):0); } return 0; }