HDU 5399 Too Simple(过程中稍微用了一下dfs)——多校练习9

本文探讨了一个数学问题,即计算在给定部分函数映射的情况下,有多少种不同的函数组合能使最终复合函数等于恒等函数。文章提供了详细的解题思路,包括如何处理未知函数以及如何通过递归实现解的计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Too Simple

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)


Problem Description
Rhason Cheung had a simple problem, and asked Teacher Mai for help. But Teacher Mai thought this problem was too simple, sometimes naive. So she ask you for help.

Teacher Mai has m functions f1,f2,,fm:{1,2,,n}{1,2,,n}(that means for all x{1,2,,n},f(x){1,2,,n}). But Rhason only knows some of these functions, and others are unknown.

She wants to know how many different function series f1,f2,,fm there are that for every i(1in),f1(f2(fm(i)))=i. Two function series f1,f2,,fm and g1,g2,,gm are considered different if and only if there exist i(1im),j(1jn),fi(j)gi(j).
 

Input
For each test case, the first lines contains two numbers n,m(1n,m100).

The following are m lines. In i-th line, there is one number 1 or n space-separated numbers.

If there is only one number 1, the function fi is unknown. Otherwise the j-th number in the i-th line means fi(j).
 

Output
For each test case print the answer modulo 109+7.
 

Sample Input
3 3 1 2 3 -1 3 2 1
 

Sample Output
1
Hint
The order in the function series is determined. What she can do is to assign the values to the unknown functions.
 
/*********************************************************************/

题意:给你m个函数f1,f2,⋯,fm:{1,2,⋯,n}→{1,2,⋯,n}(即所有的x∈{1,2,⋯,n},对应的f(x)∈{1,2,⋯,n}),已知其中一部分函数的函数值,问你有多少种不同的组合使得所有的i(1≤i≤n),满足f1(f2(⋯fm(i)))=i

对于函数集f1,f2,⋯,fm and g1,g2,⋯,gm,当且仅当存在一个i(1≤i≤m),j(1≤j≤n),fi(j)≠gi(j),这样的组合才视为不同。

如果还是不理解的话,我们来解释一下样例,

3 3

1 2 3

-1

3 2 1

样例写成函数的形式就是

n=3,m=3

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这么一种情况

解题思路:其实,仔细想想,你就会发现,此题的解跟-1的个数有关,当只有一个-1的时候,因为对应关系都已经决定了,所以只有1种可行解,而当你有两个-1时,其中一个函数的值可以根据另一个函数的改变而确定下来,故有n!种解。依此类推,当有k个-1时,解为


所以,我们只需要提前将n!计算好取模存下来,剩下的就是套公式了

有一点需要提醒的是,当-1的个数为0时,即不存在-1的情况,解并不一定为0,若不存在-1的情况下仍满足对于所有的i(1≤i≤n),满足f1(f2(⋯fm(i)))=i,输出1;否则输出0,所以加个dfs判断一下方案是否可行。多校的时候就被这一点坑了,看来还是考虑得不够多。

若对上述有什么不理解的地方,欢迎提出。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<stdlib.h>
#include<cmath>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N = 105;
const int inf = 1000000000;
const int mod = 1000000007;
__int64 s[N];
bool v[N];
int w[N][N];
int dfs(int t,int x)
{
    if(t==1)
        return w[t][x];
    return dfs(t-1,w[t][x]);
}
int main()
{
    int n,m,i,j,k,x;
    bool flag;
    __int64 ans;
    s[0]=1;
    for(i=1;i<N;i++)
        s[i]=(s[i-1]*i)%mod;
    while(~scanf("%d%d",&n,&m))
    {
        flag=true;
        for(k=0,i=1;i<=m;i++)
        {
            scanf("%d",&x);
            if(x==-1)
                k++;
            else
            {
                memset(v,false,sizeof(v));
                v[x]=true;w[i][1]=x;
                for(j=2;j<=n;j++)
                {
                    scanf("%d",&x);
                    v[x]=true;
                    w[i][j]=x;
                }
                for(j=1;j<=n;j++)
                    if(!v[j])
                        break;
                if(j<=n)
                    flag=false;
            }
        }
        /*for(i=1;i<=m;i++)
        {
            for(j=1;j<=n;j++)
                printf("%d ",w[i][j]);
            printf("\n");
        }*/
        if(!flag)
            puts("0");
        else if(!k)
        {
            for(i=1;i<=n;i++)
                if(dfs(m,i)!=i)
                    break;
            //printf("%d*\n",i);
            if(i>n)
                puts("1");
            else
                puts("0");
        }
        else
        {
            for(ans=1,i=1;i<k;i++)
                ans=ans*s[n]%mod;
            printf("%I64d\n",ans);
        }
    }
    return 0;
}
菜鸟成长记


评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值