Gcd
给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的
数对(x,y)有多少对.
Input
一个整数N
Output
如题
Sample Input
4
Sample Output
4
Hint
hint
对于样例(2,2),(2,4),(3,3),(4,2)
1<=N<=10^7
推导:
本题的本质就是
后面那个式子我们在莫比乌斯反演中已经见过很多了。
令
则有,进一步对F(x)进行推导得到:
对F(x)反演推回
则最初的式子就变成了
复杂度论证:
预处理mu[],F[],check[],以及最终处理ans都是O(1)的复杂度
主要是处理f(x)的复杂度的。
对于f(x)的处理,我们采用这样一段代码:
for(int i=1;i<=n;i++)
{
if(check[i])continue;
for(int j=i;j<=n;j+=i)
{
f[i]+=1ll*mu[j/i]*F[j];
}
}
其中的i就是x,j就是kx,可以看出来这个式子的复杂度是
这个式子求和较难,不如将它放大一点,成:
这个复杂度没有问题
AC代码:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int MAXN=1e7;
bool check[MAXN+10];
int prime[MAXN+10];
int mu[MAXN+10];
void Moblus()
{
memset(check,false,sizeof(check));
mu[1] = 1;
check[1]=true;
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];
}
}
}
}
long long F[MAXN+10],f[MAXN+10];
int main()
{
Moblus();
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) F[i]=1ll*(n/i)*(n/i);
for(int i=1;i<=n;i++)
{
if(check[i])continue;
for(int j=i;j<=n;j+=i)
{
f[i]+=1ll*mu[j/i]*F[j];
}
}
long long ans=0;
for(int i=1;i<=n;i++)if(!check[i]) ans+=1ll*f[i];
printf("%lld\n",ans);
}