bzoj2818 Gcd(反演)

Description

给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的

数对(x,y)有多少对.

Input

一个整数N

Output

如题

Sample Input

4

Sample Output

4

HINT

对于样例(2,2),(2,4),(3,3),(4,2)

1<=N<=10^7

[ Submit][ Status][ Discuss]



分析:
题目只是说GCD(x,y)是素数
我就考虑能不能直接枚举n以内的素数
由于n的范围不是特别大,我们可以预处理出n以内的所有素数

在确定了素数x之后:
这里写图片描述

这样我们就可以直接预处理出phi值得前缀和,直接“枚举+累加”即可

//这里写代码片
#include
#include
#include
#define ll long long

using namespace std;

const int N=1e7+3;
ll phi[N];
int sshu[2000000],tot=0;
bool no[N];
int n;

void make()
{
    for (int i=2;i<=n;i++) 
    {
        if (!no[i]) sshu[++tot]=i;
        for (int j=1;j<=tot&&sshu[j]*i<=n;j++)
        {
            no[sshu[j]*i]=1;
            if (i%sshu[j]==0) break;
        }
    }

    for (int i=1;i<=n;i++) phi[i]=i;
    for (int i=1;i<=tot;i++)
        for (int j=sshu[i];j<=n;j+=sshu[i])
        {
            phi[j]/=sshu[i];
            phi[j]*=(sshu[i]-1);
        }
    for (int i=2;i<=n;i++) phi[i]+=phi[i-1];
}

int main()
{
    scanf("%d",&n);
    make();
    ll ans=0;
    for (int i=1;i<=tot&&sshu[i]<=n;i++)
        ans+=(ll)(2*phi[n/sshu[i]]-1);
    printf("%lld",ans);
    return 0;
} 

你可能感兴趣的:(反演)