hdu-6038 Function 思维+模拟

版权声明:本博客内容基本为原创,如有问题欢迎联系,转载请注明出处 https://blog.csdn.net/qq_41955236/article/details/84791456

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6038

题意:

       有点复杂,耐心观看。给你一个长度为n下标从0~n-1的a数组,和一个长度为m下标从0~m-1的b数组,两个数组均为一组排序(即0~n-1种每一个数都只出现一次)。要你找出有多少种函数f的映射,使得对i\in [0,n-1],都有f(i)=b_{f(a_{i})}成立。

做法:

       重点就在这两个数组都是排序!所以对于a和b数组来说,里面的数字可以组成至少一个环,什么意思呢。假设我们在a数组中有a[1]=3,a[3]=6,a[6]=1.那么这就有1->3,3->6,6->1的一个环,环的大小(即环内的节点数)就是3。由于说明是排序,所以保证两数组中均有至少一个两两不相交的环,我们将这些环的大小和记录下来后,会发现,在我们对0~n-1进行处理时,如果a中有一个环的大小为x,b中有一个环的大小为y并且有x%y=0使,那么y中的数字可以成为x映射的对象。假设有a中有1->2,2->3,3->4,4->5,5->6,6->1,b中有  0->5,5->0时,令f(1)=0,自然就有f(2)=5,f(3)=0...,这便是一组映射,当f(1)=5时,能得到不同的映射。那么答案自然就出来了。

       我们枚举a里的每一个环,去找是否存在b里有环数等于它的因子x,如果有,那么这个环的方案要加上这个因子x*x出现的次数,最后a里每一个环的数量相乘即可。有个小细节,如果有一个环它没有可行,那么最终为0


#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=100005;
vector<ll> yinzi[maxn];
ll a[maxn],b[maxn],n,m;
map<ll,ll> numb,numa;
map<ll,ll>::iterator it;
bool visa[maxn],visb[maxn];
void init(){
    yinzi[1].pb(1);
    for(int i=2;i<maxn-2;i++){
        yinzi[i].pb(1ll);
        for(int j=i;j<maxn;j+=i){
            yinzi[j].pb((ll)i);
        }
    }
}
ll quick(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1) ans=ans*a%mod;
        a=a*a%mod;
        b/=2;
    }
    return ans;
}
int main(){
    init();
    int cas=0;
    while(~scanf("%lld%lld",&n,&m)){
        memset(visa,0,sizeof(visa));
        memset(visb,0,sizeof(visb));
        numb.clear();numa.clear();
        for(int i=0;i<n;i++)
            scanf("%lld",&a[i]);
        for(int i=0;i<m;i++)
            scanf("%lld",&b[i]);

        for(int i=0;i<n;i++){
            ll innum=0;
            if(!visa[i]){
                int now=i;
                while(!visa[now]){
                    innum++;
                    visa[now]=1;
                    now=a[now];
                }
                numa[innum]++;
            }
        }
        for(int i=0;i<m;i++){
            int innum=0;
            if(!visb[i]){
                int now=i;
                while(!visb[now]){
                    innum++;
                    visb[now]=1;
                    now=b[now];
                }
                numb[innum]++;
            }
        }
        ll ans=1;
        for(it=numa.begin();it!=numa.end();it++){
            ll aim=it->first,num=it->second;
            //cout<<aim<<" "<<num<<endl;
            ll tmpans=0;
            for(int i=0;i<yinzi[aim].size();i++){
                ll yi=yinzi[aim][i];
                tmpans+=(ll)numb[yi]*yi;
            }
            ans=(ans*quick(tmpans,num))%mod;
        }
        printf("Case #%d: %lld\n",++cas,ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41955236/article/details/84791456