BZOJ 2818 欧拉函数,线性筛

题目链接:https://www.acwing.com/problem/content/description/222/

给定整数N,求1<=x,y<=N且GCD(x,y)为素数的数对(x,y)有多少对。

GCD(x,y)即求x,y的最大公约数。

输入格式

输入一个整数N

输出格式

输出一个整数,表示满足条件的数对数量。

数据范围

1≤N≤10^7

输入样例:

4

输出样例:

4

题解:

首先,用线性筛可以预处理处素数与欧拉函数。

我们定义 count(x)为: 1<=i,j<=N 有多少对gcd(i,j)=x;

那么原问题就转化成 BZOJ 2818  欧拉函数,线性筛 (要求i是素数)

那么问题就转化成了,怎么能快速的求出count(x)

因为  count(x)为:1<=i,j<=N 有多少对gcd(i,j)=x , 那么i和j必须是x的倍数,i和j的范围是x,2x,3x.....BZOJ 2818  欧拉函数,线性筛*x

那么我们把i和j都约掉一个x,那么约掉后的i和j要求i和j互质,那么问题就转化成:

1<=i,j<=BZOJ 2818  欧拉函数,线性筛 ,有多少对数字两两互质。

那么很容易想到欧拉函数,euler(x) 是 1到x有多少对数字和x互质,然后用前缀和就可以预处出来

sum[1]=1,  sum[i]=sum[i-1]+2*euler[i]  

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e7+5;
int v[maxn],prime[maxn],cnt,phi[maxn];
ll sum[maxn];
void init(){
    for(int i=2;i<maxn;i++){
        if(!v[i]){
            prime[cnt++]=i;
            v[i]=i;
            phi[i]=i-1;
        }
        for(int j=0;j<cnt;j++){
            if(prime[j]>v[i]||prime[j]>maxn/i) break;
            v[i*prime[j]]=prime[j];
            phi[i*prime[j]]=phi[i]*(i%prime[j]?prime[j]-1:prime[j]);
        }
    }
    sum[1]=1;
    for(int i=2;i<maxn;i++) sum[i]=sum[i-1]+2*phi[i];
}
int main(){
    init();
    int n;
    cin>>n;
    ll ans=0;
    for(int i=2;i<=n;i++){
        if(v[i]==i){
            ans+=sum[n/i];
        }
    }
    cout<<ans<<endl;
    return 0;
}

 

上一篇:luogu P7287 「EZEC-5」魔法


下一篇:BZOJ 2818 GCD 欧拉函数