BZOJ 2818 gcd

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

 

f[i] 表示 1~i中  1<=x,y<=i 且(x,y)=1个对数的个数

显然 f[i] = 1+2* sigma(phi[j])  1<j <= i

 

ans = sigma(f[N/p])  p为小于N的素数

 

 

 

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 10000000+10;
int prime[N/3],phi[N],cnt = 0;  
bool flag[N];  
int n ;
long long f[N];
void get_prime()  
{  
    cnt=0;  
    memset(flag,false,sizeof(flag)); 
    for(int i=2;i<N;++i)
    {  
        if(!flag[i])
        {                              
            prime[cnt++]=i;  
            phi[i]=i-1;  
        }  
        for(int j=0; j<cnt && i*prime[j] < N ; ++j)
        {  
            flag[i*prime[j]]=true;              
            if(i%prime[j]==0)
            {  
                phi[i*prime[j]]=phi[i]*prime[j];  
                break;  
            }  
            else  
                phi[i*prime[j]]=phi[i]*(prime[j]-1);  
        }  
    }  
}  
int main()
{
    freopen("gcd.in","r",stdin);
    freopen("gcd.out","w",stdout);
    get_prime();
    cin>>n;
    f[1] = 1;
    for (int i = 2; i <= n;++i) f[i]=f[i-1]+2*phi[i];
    long long ans = 0;
    for (int i = 0; i < cnt ; ++i)
    if (prime[i] < n)
        ans += f[n/prime[i]];
    cout << ans << endl;
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值