题目
题意
给两个长度分别为 n 和 m 的数组 a 和 b ,定义一个函数 f(x),该函数满足 f(i) = bf(ai) 。
求不同 f(x) 的数量,答案模109+7。
题解
图论,这题十分的绕,有点像我们常说的你爷爷的儿子的弟弟的儿子的哥哥是你自己一样 = = 。
这题刚开始只能多举几个例子进行观察,然后会发现规律:
1. 数组 a 中要有子数组能形成自环。
2. 数组 b 中要有子数组能形成自环。
3. 当数组 b 中自环的子数组长度 lenB 为数组 a 中自环的子数组长度 lenA 的因子的时候,这两个子数组就能构成 lenB 种不同的 f(x)。
答案的形成:
1. 对于每个数组 a 的自环子数组,能形成不同的 f(x) 的数量为所有满足条件的数组 b 的自环子数组的长度的和。
2. 最终答案为所有数组 a 的自环子数组的 f(x) 数量之积,当然在计算的过程中答案要不断模109+7 。
代码
#include <algorithm>
#include <bitset>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
using namespace std;
const long long mod = 1000000007;
const int N = 100005;
int a[N],b[N];
int visA[N],visB[N];
int main(){
int n,m;
int t = 0;
while(cin >> n >> m){
memset(visA,0, sizeof(visA));
memset(visB,0, sizeof(visB));
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for (int i = 0; i < n; ++i) {
scanf("%d",&a[i]);
}
for (int i = 0; i < m; ++i) {
scanf("%d",&b[i]);
}
for (int i = 0; i < n; ++i) {
int cnt = 0;
int x = i;
while(a[x] != -1){
int temp = a[x];
a[x] = -1;
x = temp;
cnt++;
}
visA[cnt]++;
}
for (int i = 0; i < m; ++i) {
int cnt = 0;
int x = i;
while(b[x] != -1){
int temp = b[x];
b[x] = -1;
x = temp;
cnt++;
}
visB[cnt]++;
}
long long ans = 1;
for (int i = 1; i <= n; ++i) {
if (visA[i] > 0){
long long sum = 0;
int cnt = (int)sqrt(i);
for (int j = 1; j < cnt+1; ++j) {
if(i % j == 0){
if(visB[j] > 0){
sum = (sum + visB[j] * j) % mod;
}
if(j != (i / j) && visB[i / j] > 0){
sum = (sum + visB[i / j] * (i / j)) % mod;
}
}
}
for (int j = 0; j < visA[i]; ++j) {
ans = (ans * sum) % mod;
}
}
}
printf("Case #%d: %d\n",++t,ans);
}
return 0;
}