hdu5399(2015多校9)--Too Simple

题目链接:点击打开链接

题目大意:有m个映射,从1到n映射到1到n,记为f1,f2,f3,,,fm,并且这些映射满足f1( f2( f3(,,,,fm(i) ) ) ) = i现在已知几个映射的值,还有几个映射是不知道的,问不知道的映射一共有几种可能的组合方式。

输入n m,之后m行,如果一行的第一个数为-1,代表这一个映射fi是不知道的,否则一行有n个数,第i行的第j个数字x代表fi(j) = x

问最终的种类(对1e9+7取余)

1、如果映射不是单射,也就是存在fi(x) = fi(y)并且x!=y,那么就不可能满足关系式,输出0

2、如果所有的映射都已经给出,那么判断是不是映射都符合条件,如果符合输出1,否则输出0

3、假设存在num个未知的映射,那么这num个未知的映射一定都是单射,我们要保证满足公式只需要对最小的一个映射进行调控,就可以了,之后的映射不论怎么样变化,都可以通过改变最小的映射,使得整体满足条件。所以对于一个映射的全排列n!种,然后n!*(num-1)

#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <cmath>
#include <map>
#include <stack>
#include <time.h>
#include <algorithm>
using namespace std ;
#pragma comment(linker, "/STACK:102400000,102400000")
#define LL __int64
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int Mod = 1e9+7;
int vis[110] , a[110][110] ;
LL ans , s ;
int main() {
    int n , m , x , i , j , flag , num ;
    while( scanf("%d %d", &n, &m) !=EOF ) {
        for(i = 1 , s = 1 ; i <= n ; i++) s = s*i%Mod ;
        num = flag = 0 ;
        for(i = 1 ; i <= m ; i++) {
            memset(vis,0,sizeof(vis)) ;
            for(j = 1 ; j <= n ; j++) {
                scanf("%d", &a[i][j]) ;
                if( a[i][j] == -1 ) {
                    num++ ;
                    break ;
                }
                vis[ a[i][j] ]++ ;
                if( vis[ a[i][j] ] == 2 ) flag = 1 ;
            }
            if( j <= n ) continue ;
        }
        if( flag ) {
            printf("0\n") ;
            continue ;
        }
        if( num == 0 ) {
            for(i = 1 ; i <= n ; i++) {
                x = i ;
                for(j = m ; j > 0 ; j--)
                    x = a[j][x] ;
                if( x != i ) break ;
            }
            if( i <= n ) printf("0\n") ;
            else printf("1\n") ;
            continue ;
        }
        ans = 1 ;
        for(i = 1 ; i < num ; i++)
            ans = ans*s%Mod ;
        printf("%I64d\n", ans) ;
    }
    return 0 ;
}


你可能感兴趣的:(hdu5399(2015多校9)--Too Simple)