题目链接:hdu6038
题目大意:a数组有n个元素(0 ~ n-1),b数组有m个元素(0 ~ m-1),定义一个函数 f ,使 f(i) = b[f(ai)],求满足条件的 f 函数有多少种
例如 3 2
a 1 0 2 f (0) = b [f(1)] 所以可能的结果有 4 (2*2) 种,
b 0 1 f (1) = b [f(0)] ① f (0) = f (1) = 0 或 f (0) = f (1) = 1
f (2) = b [f(2)] ② f (2) = 0 或 f (2) = 1
思路:a 和 b 中的每个元素都属于一个环,可以发现只有当 b 里环数为 a 里环数 的因数时,可以将 b 环中的值填入 a 环里,对于 b 环,每个环的元素个数就是这个环填入一个a环时的情况数(举例可知),例如:a 形成的环(假设均为m个): 2 环, 3 环,4 环; b 形成的环(假设均为k个): 1 环,2 环, 3 环, 4 环。则将b环中的数填入a环中:
2 环(a)里包含: 1、2环 (b) , 每个环有 1*k1 + 2*k2 种情况, 则 m 个环共有 (1*k1 + 2*k2 )^ m1 种情况
3 环包含 1、3环; 4 环包含1、2、4环
CODE:
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <string>
#include <algorithm>
#define maxn 100005
#define mod (1000000000+7)
typedef long long ll;
using namespace std;
ll mp[2][maxn];
ll vis[maxn], f[maxn];
ll fun(ll x, ll n)
{
ll ans = 1;
while (n) {
if (n & 1) ans = (ans*x) % mod;
x = x*x%mod;
n >>= 1;
}
return ans;
}
void Ring(int n, int u)
{
memset(vis, 0, sizeof(vis));
for (int i = 0; i < n; i++)
scanf("%lld", &f[i]);
for (int i = 0; i < n; i++) {
int k = i, cot = 0;
if (k == f[k] && !vis[k]) {
mp[u][1]++;
continue;
}
if (!vis[k]) {
while (k != f[k] && !vis[k]) {
vis[k] = 1;
k = f[k];
cot++;
}
if (k == f[k] && !vis[k])
continue;
mp[u][cot]++;
}
}
}
ll k[maxn],a[maxn],numa[maxn],b[maxn],numb[maxn];
int main()
{
int n, m, cas = 1;
while (~scanf("%d%d", &n, &m)) {
memset(mp, 0, sizeof(mp));
memset(k, 0, sizeof(k));
Ring(n, 0); //得到环,mp[0][k]表示a中k环的个数
Ring(m, 1); //mp[1][k]表示b中k环的个数
ll ans = 1,cota = 1,cotb = 1;
for (int i = 1; i <= n || i <= m; i++) { //o(n)将所需的数列出,降低循环次数
if (mp[0][i]) {
a[cota] = mp[0][i];
numa[cota++] = i;
}
if (mp[1][i]) {
b[cotb] = mp[1][i];
numb[cotb++] = i;
}
}
for (int i = 1; i < cota; i++) {
for (int j = 1; j < cotb; j++) {
if (numa[i] % numb[j] == 0) {
k[i] = (k[i]%mod + numb[j]*b[j] % mod) % mod; //1个a环的所有情况加起来
}
}
}
for (int i = 1; i < cota; i++) {
ans *= fun(k[i], a[i]);
}
printf("Case #%d: %lld\n", cas++, ans);
}
return 0;
}