HDU 6038 - Function | 2017 Multi-University Training Contest 1

/*
HDU 6038 - Function [ 置换,构图 ]
题意:
	给出两组排列 a[], b[]
	问 满足 f(i) = b[f(a[i])] 的 f 的数目
分析:
	假设 a[] = {2, 0, 1}
	则 	f(0) = b[f(2)]  
		f(1) = b[f(0)] 
		f(2) = b[f(1)]
	即	f(0) = b[b[b[f(0)]]]
		f(1) = b[b[b[f(1)]]]
		f(2) = b[b[b[f(2)]]]
	由于将 a[i]->i 连边可以得到不相交的多个循环
	可以看出对于 a[] 中的每一个循环,满足条件 f 的个数即 b[] 中循环长度为其循环长度约数的循环
	故对于a中每个循环,找出b中循环长度为其长度的约数的循环个数,再把每个循环的个数乘起来
*/
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const LL MOD = 1e9+7;
const int N = 1e5+5;
int n, m;
int a[N], b[N];
int fa[N], fb[N];
int sa[N], sb[N];
int num[N];
int sf(int x, int f[]) {
	return x == f[x] ? x : f[x] = sf(f[x], f);
}
int main()
{
    int tt = 0;
	while (~scanf("%d%d", &n, &m))
	{
		for (int i = 0; i <= max(n, m); i++)
        {
            fa[i] = fb[i] = i;
            sa[i] = sb[i] = num[i] = 0;
        }
		for (int i = 0; i < n; i++) {
			scanf("%d", &a[i]);
			fa[sf(i,fa)] = sf(a[i], fa);
		}
		for (int i = 0; i < m; i++) {
			scanf("%d", &b[i]);
			fb[sf(i,fb)] = sf(b[i], fb);
		}
		for (int i = 0; i < n; i++) sa[sf(i, fa)]++;
		for (int i = 0; i < m; i++) sb[sf(i, fb)]++;
		for (int i = 0; i < m; i++) num[sb[i]]++;
		LL ans = 1;
		for (int i = 0; i < n; i++)
        {
            if (sa[i])
            {
                LL cnt = 0;
                for (int j = 1; (LL)j*j <= sa[i]; j++)
                {
                    if (sa[i] %j == 0)
                    {
                        int k = sa[i] / j;
                        cnt = (cnt + (LL)j*num[j]) % MOD;
                        if (k != j) cnt = (cnt + (LL)k*num[k]) % MOD;
                    }

                }
                ans = ans * cnt % MOD;
            }
        }
        printf("Case #%d: %lld\n", ++tt, ans);
	}
}

  

posted @ 2017-07-27 21:06  nicetomeetu  阅读(204)  评论(0编辑  收藏  举报