hdu 5399 Too Simple

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5399

解题思路:

题目大意:

给m个函数,其对应是自变量x属于{1,2,...n},f(x)属于{1,2...n},给出其中一些函数,问有多少种不同的函数集合,使得1<=i<=n,f1(f2(f3...fm(i))) = i。

解释样例:

3 3

1 2 3

-1

3 2 1

样例写成函数的形式就是

n=3,m=3(m行,每行n个数)

f1(1)=1,f1(2)=2,f1(3)=3

f2(1)、f2(2)、f2(3)的值均未知

f3(1)=3,f3(2)=2,f3(3)=1

所以要使所有的i(1≤i≤n),满足f1(f2(⋯fm(i)))=i,只有一种组合情况,即f2(1)=3,f2(2)=2,f2(3)=1

官方题解:

首先要求每个f_ifi是个排列,否则如果某个f_ifi将两个数映射向同一个数,那么最后这两个数得到的值一定相同。

如果还剩一个位置为-11,那么这个排列是唯一确定的,假设X*f_i*Y=IXfiY=I,那么f_i=X^{-1}*Y^{-1}fi=X1Y1.

所以假设有c(c\geq 1)c(c1)-11,那么答案为(n!)^{c-1}(n!)c1个可行的方案。

算法思想:

当某一行的映射不能保证一对一时(换句话说就是多对一),那么一定存在i(1≤i≤n)不满足f1(f2(⋯fm(i)))=i,此时结果为0。除了这种特殊情况,最后的解只跟-1的个数有关,当-1的个数是0时,结果未必是0,,要判断对所有的i是否都满足条件,如果满足,结果是1,否则结果是0。当只有一个-1的时候,因为对应关系都已经确定了,所以只有1种可行解,而当有两个-1时,其中一个函数的值可以根据另一个函数的改变而确定下来,故有n!种解。依此类推,当有k个-1时,解为(n!)^(k-1)(k>0)。


AC代码:

#include <iostream>  
#include <cstdio>  
#define MOD 1000000007  
using namespace std;  
typedef long long ll;  
int n,m;  
ll f[105],a[105][105];  
  
int main(){  
    f[0] = 1;  
    for(int i = 1; i <= 100; i++)  
        f[i] = f[i-1]*i%MOD;  
    while(~scanf("%d%d",&n,&m)){  
        ll tot = 0,ans = 1;  
        for(int i = 1; i <= m; i++){  
            scanf("%lld",&a[i][1]);  
            if(a[i][1] == -1)  
                tot++;  
            else{  
                for(int j = 2; j <= n; j++){  
                    scanf("%lld",&a[i][j]);  
                    for(int k = j-1; k >= 1; k--)  
                        if(a[i][j] == a[i][k])  
                            ans = 0;  
                }  
            }  
        }  
        for(int i = 1; i < tot; i++)  
            ans = ans*f[n]%MOD;  
        if(tot == 0){  
            for(int i = 1; i <= n; i++)  
                a[0][i] = i;  
            for(int i = m; i>= 1; i--)  
                for(int j = 1; j <= n; j++)  
                    a[0][j] = a[i][a[0][j]];//映射转换
            for(int i = 1; i <= n; i++)  
                if(a[0][i] != i)  
                    ans = 0;//如果不能变回原来的数列,则为0
        }  
        printf("%lld\n",ans);  
    }  
    return 0;  
}  




你可能感兴趣的:(找规律)