记录一个菜逼的成长。。
题目链接
序列变换
alpq654321 (命题人)
基准时间限制:1 秒 空间限制:131072 KB 分值: 40
lyk有两序列a和b。
lyk想知道存在多少对x,y,满足以下两个条件。
1:
gcd(x,y)=1
2:
abx=bay
例如若a={1,1,1},b={1,1,1}。那么存在7对,因为除了x=2,y=2或x=3,y=3外都满足条件。
Input
第一行一个数n(1<=n<=100000)。
接下来一行n个数,表示ai(1<=ai<=n)。
接下来一行n个数,表示bi(1<=bi<=n)。
Output
一行表示答案
Input示例
3
1 1 1
1 1 1
Output示例
7
官方题解:
如果没有gcd(x,y)=1的限制。
那么我们可以直接将所有b(ax)全部存进一个数组里。
然后将所有b(ay)出现的次数统计进答案里就可以了。
问题的关键是怎么处理这个限制。
我们可以考虑容斥。
即先把所有解都累加进答案,然后去掉gcd(x,y)!=1的解。
这里我们可以用莫比乌斯函数。
令设x为i在质因数分解中数的个数,y为i质因数分解后是否存在相同质因数。
那么若y=1则u[i]=0;否则
若x%2=1则u[i]=-1;否则
u[i]=1。
注意这里u[1]=1。
接下来我们只要计算出x,y都为t的倍数时的答案,再与u[t]相乘累加进答案就可以了。
总复杂度nlgn。
个人感觉官方题解讲的好复杂的样子。
我感觉就是莫比乌斯反演
假设,以下x,y都满足第二个条件
f(k) 表示gcd(x,y) == k的个数
F(k) 表示gcd(x,y) == k的倍数 的个数
然后就是
f(k)=∑nd=1μ(d)∗F(d)
这题F(d)不能直接算了,需要枚举k的倍数,用个数组统计满足第二个条件的个数
#include <bits/stdc++.h>
using namespace std;
#define cl(a,b) memset(a,b,sizeof(a))
typedef long long LL;
const int maxn = 100000 + 10;
bool check[maxn];
int mu[maxn],prime[maxn];
void Mobius()
{
cl(check,false);
mu[1] = 1;
int tot = 0;
for( int i = 2; i < maxn; i++ ){
if(!check[i]){
prime[tot++] = i;
mu[i] = -1;
}
for( int j = 0; j < tot; j++ ){
if(i * prime[j] >= maxn)break;
check[i*prime[j]] = true;
if(i % prime[j] == 0){
mu[i * prime[j]] = 0;
break;
}
else {
mu[i * prime[j]] = -mu[i];
}
}
}
}
int a[maxn],b[maxn],vis[maxn],n;
LL cal(int t)
{
LL ret = 0;
for( int i = t; i <= n; i += t )vis[b[a[i]]]++;
for( int i = t; i <= n; i += t )ret += vis[a[b[i]]];
for( int i = t; i <= n; i += t )vis[b[a[i]]]--;
return ret;
}
int main()
{
Mobius();
while(~scanf("%d",&n)){
for( int i = 1; i <= n; i++ ){
scanf("%d",a+i);
}
for( int i = 1; i <= n; i++ ){
scanf("%d",b+i);
}
LL ans = 0;
for( int i = 1; i <= n; i++ ){
ans += mu[i]*cal(i);
}
printf("%lld\n",ans);
}
return 0;
}