BZOJ 2818 GCD 素数筛+欧拉函数+前缀和

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2818

题意:给定整数N,求1<=x,y<=n且Gcd(x,y)为素数的数对(x,y)有多少对

思路:先筛出n以内所有的素数顺便筛出欧拉函数,\(gcd(x,y)=k\)等价于\(gcd(\frac{x}{k},\frac{y}{k})=1\)

所以这个问题可以转化为求\(ans=\sum_{i=1}^{tot}\sum_{j=1}^{n/prime[i]}phi[j]\) ,tot为n以内素数个数,

这个公式可以前缀和优化,暴力枚举也能过,而且时间居然只慢了20ms....

求得的结果只是一半的情况,当\(x\not=y,(x,y)\not=(y,x)\),而x=y的情况只有tot种,(2,2),(3,3),(5,5)....(prime[tot],prime[tot]),

所以答案为\(ans*2-tot\)

```c++
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;
const double PI=acos(-1.0);
const double eps=1e-6;
const ll inf=1e18;
const int mod=1e9+7;
const int maxn=1e7+10;
bool b[maxn];
int prime[maxn],tot,n;
ll phi[maxn];
void init(int n){
    b[0]=b[1]=phi[1]=1;
    for(int i=2;i<=n;i++){
        if(!b[i]){
            prime[++tot]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=tot;j++){
            if(i*prime[j]>n) break;
            b[i*prime[j]]=1;
            phi[i*prime[j]]=phi[i]*phi[prime[j]];
            if(i%prime[j]==0){
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
        }
    }
    for(int i=1;i<=n;i++) phi[i]+=phi[i-1];
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n;
    init(n);
    ll ans=0,cnt=0;
    for(int i=1;i<=tot;i++){
        ans+=phi[n/prime[i]];
    }
    cout<<ans*2-tot<<endl;
    return 0;
}
```
全部评论

相关推荐

我已成为0offer的糕手:别惯着,胆子都是练出来的,这里认怂了,那以后被裁应届被拖工资还敢抗争?
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务