http://acm.hdu.edu.cn/showproblem.php?pid=6038
Function
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1607 Accepted Submission(s): 753
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
10^9+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
分析
题意:给定一个关系式 f(i)=b[f(a[i])] 和数组a,b,计算满足这个关系式不同的可能性数目
可以转化为求环的问题,有多少种方式可以构成题目要求的环,即b的环可以有多少种方式画成a的环
样例一:
i: 0,1,2
a: 1,0,2
b: 0,1
根据关系式 f(i)=b[f(a[i])] 可得
///a环
f(0)=b[f(a[0])]=b[f(1)]
f(1)=b[f(a[1])]=b[f(0)]
f(2)=b[f(a[2])]=b[f(2)]
///易看出a[0]和a[1]组成一个环,a[2]单独成环
///b环
如果f(0)=b[0]
因为f(0)=b[f(1)],则f(1)=0=b[0]
因为f(1)=b[f(0)],则f(0)=0=b[0]
如果f(0)=b[1]
因为f(0)=b[f(1)],则f(1)=1=b[1]
因为f(1)=b[f(0)],则f(0)=1=b[1]
///易看出b[0]单独成环,b[1]单独成环
由图易知,a的两个环都可以由b的两个环构成,则由b构成a总共有2+2=4种方式。
样例二:
i: 0,1,2,3
a: 2,0,1
b: 0,2,3,1
根据关系式 f(i)=b[f(a[i])] 可得
///a环
f(0)=b[f(a[0])]=b[f(2)]
f(1)=b[f(a[1])]=b[f(0)]
f(2)=b[f(a[2])]=b[f(1)]
///易看出a[0],a[1],a[2]组成一个环
///b环
如果f(0)=b[0]
因为f(0)=b[f(2)],则f(2)=0=b[0]
因为f(2)=b[f(1)],则f(1)=0=b[0]
因为f(1)=b[f(0)],则f(0)=0=b[0]
如果f(0)=b[1]
因为f(0)=b[f(2)],则f(2)=1=b[3]
因为f(2)=b[f(1)],则f(1)=3=b[2]
因为f(1)=b[f(0)],则f(0)=2=b[1]
///易看出b[0]单独成环,b[1],b[2],b[3]组成一个环
由图易知,a的一个环可以由b的两个环构成,但b的第二个环与a环可以有三种不同的对应关系,则由b构成a总共有1+3=4种方式。
所以也就是b环长度应为a环长度的因数才能满足与a环的对应关系,只要这个思路明白了,代码很好理解,记得不断对1e9+7取余
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int MOD=1e9+7;
const int maxn=100100;
int n,m,cal[2][maxn],a[maxn],b[maxn],ans=1;
///cal[0][i]表示b环中长度为i的环出现的次数
///cal[1][i]表示a环中长度为i的环出现的次数
bool vis[maxn];
///vis[i]表示位置i是否出现过,出现过则说明成环
void dfs(int t, int l, int *a, int k)
{
if(vis[t])
{
cal[k][l]++;
return;
}
vis[t] = 1;
dfs(a[t],l+1,a,k);
}
int main()
{
int ca = 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(cal,0,sizeof(cal));
memset(vis,0,sizeof(vis));
for(int i=0; i<m; i++)
if(!vis[i])dfs(i,0,b,0);
memset(vis,0,sizeof(vis));
for(int i=0; i<n; i++)
if(!vis[i])dfs(i,0,a,1);
ans=1;
for(int i=1; i<=n; i++)
if(cal[1][i])
{
int lim=(int)sqrt(i+0.5),ta = 0;
for(int j=1; j<=lim; j++)
if(i%j==0)
{
(ta+=(ll)cal[0][j]%MOD*j%MOD)%=MOD;
if(j*j!=i)ta+=((ll)cal[0][i/j]%MOD*(i/j)%MOD)%MOD;
}
for(int j=1; j<=cal[1][i]; j++)
ans=(ll)ans*ta%MOD;
}
printf("Case #%d: %d\n",++ca,ans);
}
return 0;
}