转载请注明出处,谢谢http://blog.csdn.net/bigtiao097?viewmode=contents
2017年多校联合第一场第6题
题意:
给你一个0~n-1的排列和一个0~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.
结果%1e9+7,m、n的范围均为1e5
思路:
对于0~m-1这个排列,先计算一下长度为i的循环节个数为h[i]
然后对于0~n-1这个排列中,对于长度为x的一个循环节,那么 f(i) 的值在0~m-1这个排列中所在的循环节的长度必须为 x的因数,这样枚举x的每一个因数,可以根据h数组O(1)的求出对应的数量
具体代码如下:
Result:Accepted Memory: 3328K Time : 592MS
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 1e5+5;
int a[maxn];
int b[maxn];
ll h[maxn];
bool vis[maxn];
int n,m;
ll cnt;
int Case=0;
ll ans,temp;
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(h,0,sizeof h);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<m;i++)
scanf("%d",&b[i]);
printf("Case #%d: ",++Case);
memset(vis,0,sizeof vis);
for(int i=0;i<m;i++)
{
if(vis[i])continue;
cnt=0;
while(!vis[i])
{
vis[i]=1;
i = b[i];
cnt++;
}
h[cnt]++;
}
ans = 1;
memset(vis,0,sizeof vis);
for(int i=0;i<n;i++)
{
if(vis[i])continue;
cnt=0;
while(!vis[i])
{
vis[i]=1;
i = a[i];
cnt++;
}
temp = 0;
for(int j=cnt;j>=1;j--)
{
if(cnt%j==0)
temp = (temp+((j*h[j])%mod))%mod;
}
ans = (ans*temp)%mod;
}
printf("%lld\n",ans);
}
}