题意:给出两个序列 a 和 b ,求满足 f(i)=bf(ai) 的函数个数
题解:多校联盟里的题目,记得当时是队友搞的,那时没学置换等概念,其实就是模板题。。。
看题上给的映射关系,可以看出,i与a[i],f(i)与b[i].....发现没有,就是找循环节。
其实这种映射还有另一种表示形式:
f
这样应该更直观点,其实我们在纸上算算两个样例,大致就能发现是找循环节了。。。
我们首先找出a中所有的循环节,并保存长度,可以发现同一个循环节中只要确定一个数,其他数就都确定了。
但是我们此时只是找到了i与a[i],满足的个数,但其实上式已经直观表示出来了,我们需要找出b中所有的循环节,
我们发现 f(i) 的值在置换 b 中所在的循环节的长度必须为 l 的因数(其中l为a中某循环节的因数)。。。。
然后求ans就好啦。
#include<vector>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define maxn 200010
#define mod 1000000007
int a[maxn],b[maxn];
vector<int>aa,bb;
bool vis[maxn];
void find(int a[],int n,vector<int> &aa)
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
if(vis[i])
continue;
int now=a[i],len=0;
while(!vis[now])
{
len++;
vis[now]=1;
now=a[now];
}
aa.push_back(len);
}
}
int main(void)
{
int n,m,i,j,cases=0;
while(scanf("%d%d",&n,&m)!=EOF)
{
aa.clear();
bb.clear();
for(i=1;i<=n;i++)
scanf("%d",&a[i]),a[i]++;
for(i=1;i<=m;i++)
scanf("%d",&b[i]),b[i]++;
find(a,n,aa);
find(b,m,bb);
long long ans=1;
int len1=aa.size();
int len2=bb.size();
for(i=0;i<len1;i++)
{
long long res=0;
for(j=0;j<len2;j++)
if(aa[i]%bb[j]==0)
res=(res+bb[j])%mod;
ans=(ans*res)%mod;
}
printf("Case #%d: %lld\n",++cases,ans);
}
return 0;
}