Problem Description
You are given a permutation a from 0 to n−1 and a permutation b from 0 to m−1.
Define that the domain of function f is the set of integers from 0 to n−1, and the range of it is the set of integers from 0 to m−1.
Please calculate the quantity of different functions f satisfying that f(i)=bf(ai) for each i from 0 to n−1.
Two functions are different if and only if there exists at least one integer from 0 to n−1 mapped into different integers in these two functions.
The answer may be too large, so please output it in modulo 109+7.
Input
The input contains multiple test cases.
For each case:
The first line contains two numbers n, m. (1≤n≤100000,1≤m≤100000)
The second line contains n numbers, ranged from 0 to n−1, the i-th number of which represents ai−1.
The third line contains m numbers, ranged from 0 to m−1, the i-th number of which represents bi−1.
It is guaranteed that ∑n≤106, ∑m≤106.
Output
For each test case, output “Case #x: y” in one line (without quotes), where x indicates the case number starting from 1 and y denotes the answer of corresponding case.
Sample Input
3 2
1 0 2
0 1
3 4
2 0 1
0 2 3 1
Sample Output
Case #1: 4
Case #2: 4
题意:给你一个a序列,代表0到n-1的排列;一个b序列代表0到m-1的排列。问你可以找出多少种函数关系,满足f(i)=b[f(a[i])]
解法:
看一下第二组样例:
对于这个样例,假如我们确定了f(0)在b中的值,那么根据第二个式子,就可以得到f(1),同理通过f(1)可以得到f(2),最后根据f(2)反推回来就可以判断f(0)是不是正确。也就是说,对于a中的一个循环节只要确定其中一个数映射的值,那么这个循环节其他的数就确定了。
所以我们需要先计算a,b的循环节和每个循环节节的个数,然后根据循环节的约数关系就可以判断是否成立。
如何求答案呢?当b中的循环节的长度是a的循环节长度的约数的时候,a循环节可以指定数字的个数是b的循环节长度。这里有一个规律就是:0~n 的排列,是一定存在循环节的,而且多个循环节是不会有交叉的,所以最后的结果应该相乘。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod = 1e9+7;
const int maxn = 1e5+6;
int n, m, a[maxn], b[maxn], loop_a[maxn], loop_b[maxn], vis[maxn];
LL qsm(int a, int n)
{
int ret = 1;
while(n){
if(n&1) ret=1LL*ret*a%mod;
a=1LL*a*a%mod;
n>>=1;
}
return ret;
}
int main()
{
int ks = 0;
while(~scanf("%d %d", &n,&m)){
for(int i=0; i<n; i++) scanf("%d", &a[i]);
for(int i=0; i<m; i++) scanf("%d", &b[i]);
memset(vis, 0, sizeof(vis));
memset(loop_a, 0, sizeof(loop_a));
memset(loop_b, 0, sizeof(loop_b));
for(int i=0; i<n; i++){
if(!vis[i]){
int x = a[i];
int cnt = 0;
while(!vis[x]){
cnt++;
vis[x]=1;
x=a[x];
}
loop_a[cnt]++;
}
}
memset(vis, 0, sizeof(vis));
for(int i=0; i<m; i++){
if(!vis[i]){
int x = b[i];
int cnt = 0;
while(!vis[x]){
cnt++;
vis[x]=1;
x=b[x];
}
loop_b[cnt]++;
}
}
LL ans=1;
for(int i=1; i<=n; i++){
LL ret = 0;
for(int j=1; j*j<=i; j++){
if(i%j==0){
int k = j;
ret += 1LL * loop_b[j] * j;
if(j*j != i){
k = i / j;
ret += 1LL * loop_b[k] * k;
}
}
}
int x = loop_a[i];
ans = 1LL * ans * qsm(ret, x)%mod;
}
printf("Case #%d: %lld\n", ++ks, ans);
}
return 0;
}