2017多校第一场(HDU6038)

还是太菜了这么多人过的一道题目,自己却想了这么久,然而到现在还是不是很清楚这个东西,先写一个题解吧,题目给的是一个公式 f(i)=bf(ai)
给定了b数组和a数组,然后问有多少种映射的方案满足上式,
首先来看下样例
f(0)=bf(1)
f(1)=bf(0)
f(2)=bf(2)
很容易看出 如果在a数组上从0开始,每次以a的值跳转,那么就形成上面的循环节。现在a的循环节确定了,在来看b,对于上述式子,其实b也是在循环 ,但是f的值可以重复,所以其实b的循环节可以是a的循环节的因子,然后就是求一个b的循环节放进a的情况数,因为可以是从b的任何一个点开始然后就是把b的循环节如果是a的因子,乘以a的该循环节长度就可以了,注意多个因子应该加在一起在往答案上乘
代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cstring>

using namespace std;
#define LL long long
int a[100005];
int b[100005];
LL lenb[100005];
bool vis[100005] = {false};
const LL MOD = 1e9+7;
LL Dfs(int i,int num[])
{
    vis[i] = true;
    int id = num[i];
    if(vis[id])return 1;
    return Dfs(id,num)+1;
}
int main()
{
    int n,m;
    int _case = 0;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(lenb,0,sizeof(lenb));
        for(int i = 0;i<n;i++)
        {
            scanf("%d",&a[i]);
        }
        for(int i = 0;i<m;i++)
        {
            scanf("%d",&b[i]);
        }
        vector<int>lena;
        memset(vis,0,sizeof(vis));
        for(int i = 0;i<n;i++)
        {
            if(!vis[i])
            lena.push_back(Dfs(i,a));
        }
        memset(vis,0,sizeof(vis));
        for(int i = 0;i<m;i++)
        {
            if(!vis[i])
            {
                lenb[Dfs(i,b)]++;
            }
        }
        LL fans = 1;
        for(int i = 0;i<lena.size();i++)
        {
            LL ans = 0;
            for(int j = 1;j<=lena[i];j++)
            {
                if(lena[i]%j==0)
                {
                    if(lenb[j]>0)
                    {
                        ans += j*lenb[j];
                    }
                }
            }
            ans%=MOD;
            fans *= ans;
            fans%=MOD;
        }
        printf("Case #%d: %lld\n",++_case,fans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值