HDU 5399 数学 Too Simple

题意:有m个1~n的映射,而且对于任意的 i 满足 f1(f2(...fm(i))) = i

其中有些映射是知道的,有些是不知道的,问一共有多少种置换的组合。

分析:

首先这些置换一定是1~n的一个置换(也就是1~n的一个排列)才行,因为如果某两个数映射到同一个数的话,那么这个数往后无论怎么映射,这两个数最终映射的结果还是一样的。

如果所有的f都给出来的话,那么只要判断一下就行。

 

如果有一个置换不知道的话,这个置换是可以通过前后的置换计算出来的,所以只有唯一解。

如果有两个置换不知道的话,第一个置换可以任意确定,有n!种情况,第二个置换根据第一个置换确定。

以此类推,有c个未知的置换的话,其中c-1个可以自由确定,而且互补影响,最后一个置换根据前面所有置换唯一确定,所以中的方案数是(n!)c-1

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 typedef long long LL;
 7 
 8 const int maxn = 100 + 10;
 9 const LL MOD = 1000000007;
10 
11 int n, m;
12 bool vis[maxn];
13 int a[maxn][maxn];
14 
15 inline LL mul_mod(LL a, LL b) { return a * b % MOD; }
16 
17 LL pow_mod(LL a, int n)
18 {
19     LL ans = 1LL, base = a;
20     while(n)
21     {
22         if(n & 1) ans = mul_mod(ans, base);
23         base = mul_mod(base, base);
24         n >>= 1;
25     }
26     return ans;
27 }
28 
29 LL fac[maxn];
30 
31 int main()
32 {
33     fac[0] = 1;
34     for(int i = 1; i < maxn; i++) fac[i] = fac[i - 1] * i % MOD;
35 
36     while(scanf("%d%d", &n, &m) == 2 && n)
37     {
38         int cnt = 0;
39         bool ok = true;
40         for(int i = 1; i <= m; i++)
41         {
42             scanf("%d", &a[i][1]);
43             if(a[i][1] == -1) { cnt++; continue; }
44             for(int j = 2; j <= n; j++) scanf("%d", &a[i][j]);
45             memset(vis, false, sizeof(vis));
46             for(int j = 1; j <= n; j++)
47             {
48                 if(vis[a[i][j]]) { ok = false; break; }
49                 vis[a[i][j]] = true;
50             }
51         }
52         if(!ok) { puts("0"); continue; }
53 
54         if(!cnt)
55         {
56             bool ok = true;
57             for(int i = 1; i <= n; i++)
58             {
59                 int t = i;
60                 for(int j = m; j >= 1; j--) t = a[j][t];
61                 if(t != i) { ok = false; break; }
62             }
63             if(ok) puts("1"); else puts("0");
64         }
65         else printf("%I64d\n", pow_mod(fac[n], cnt - 1));
66     }
67 
68     return 0;
69 }
代码君

 

posted @ 2015-08-19 20:08  AOQNRMGYXLMV  阅读(178)  评论(0编辑  收藏  举报