1. 程式人生 > >hdu-6038 Function 思維+模擬

hdu-6038 Function 思維+模擬

題目連結: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;
}