转自:http://blog.csdn.net/cysjiang/article/details/76090902
题意:
给你一个a序列,代表0到n-1的排列;一个b序列代表0到m-1的排列。问你可以找出多少种函数关系,满足f(i)=b[f(a[i])];
分析:这个主要是找循环节
比如说:如果 a 序列是 2 0 1 那么我们可以发现
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)]
那么f(0) f(1) f(2) 也是循环的 如果想找出这样的函数,必须值域里也存在同样长度的循环节或者存在其约数长度的循环节。
那么就是找两个序列的循环节,对于定义域里面的每一个循环节都找出来有多少种和他对应的。最后乘起来就是答案了
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+100;
int a[N],b[N],num1[N],num2[N];
typedef long long ll;
const int mod = 1e9+7;
int main()
{
int n,m;
int cas=1;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(num2,0,sizeof(num2));
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<m;i++)
scanf("%d",&b[i]);
int totfa=0;
for(int i=0;i<n;i++)
{
int k=i;
int tot=0;
while(a[k]!=-1)
{
int t=k;
k=a[k];
a[t]=-1;
tot++;
}
if(tot)num1[totfa++]=tot;
}
for(int i=0;i<m;i++)
{
int k=i;
int tot=0;
while(b[k]!=-1){
int t=k;
k=b[k];
b[t]=-1;
tot++;
}
if(tot)num2[tot]++;
}
long long total=1;
for(int i=0;i<totfa;i++)
{
ll tol=0;
for(int j=1;j*j<=num1[i];j++)
{
if(j*j==num1[i])
{
tol=(tol+num2[j]*j)%mod;
}
else if(num1[i]%j==0){
tol=(tol+num2[j]*j%mod+num2[num1[i]/j]*(num1[i]/j)%mod)%mod;
}
}
total*=tol;
total%=mod;
}
printf("Case #%d: %lld\n",cas++,total);
}
}