1. 程式人生 > >BZOJ 2818: Gcd(尤拉函式)

BZOJ 2818: Gcd(尤拉函式)

Description

給定整數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

題目思路:

假設gcd(x,y) = s;

則s是一個素數,且s*a=x;s*b=y;

則a,b互質,gcd(a,b)=1;

我們列舉素數s,求出所有的y<=n的x的個數,則預處理一個字首和代表所有小於等於t的尤拉函式值的和sum[t]。

則對於任意一個素數滿足條件的個數有sum[n/prime[i]]*2-1(有序對交換,所以乘2,捨去(1,1)特解,減一)。

程式碼:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<map>

using namespace std;

#define FOU(i,x,y) for(int i=x;i<=y;i++)
#define FOD(i,x,y) for(int i=x;i>=y;i--)
#define MEM(aA,val) memset(a,val,sizeof(a))
#define PI acos(-1.0)

const double EXP = 1e-9;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const ll MINF = 0x3f3f3f3f3f3f3f3f;
const double DINF = 0xffffffffffff;

const int N = 1e7+5;

int sum[N];
int phi[N],prime[N];
int tot;  //計數,表示prime[N]中有多少質數
void Euler(int n){  ////篩出所有小於等於n的尤拉函式值和素數
    memset(phi,0,sizeof(phi));
    tot=0,phi[1]=1;
    for(int i=2;i<=n;i++){
        if(!phi[i]){
            phi[i] = i-1;
            prime[tot++]=i;
        }
        for(int j=0;j<tot&&1ll*i*prime[j]<=n;j++){
            if(i%prime[j]!=0) phi[i*prime[j]] = phi[i] * (prime[j]-1);
            else{
                phi[i*prime[j]] = phi[i]*prime[j];
                break;
            }
        }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    std::ios::sync_with_stdio(false);
    int n;
    while(cin>>n)
    {
        Euler(n);
        sum[0]=0;
        for(int i=1;i<=n;i++)
            sum[i] = sum[i-1]+phi[i];
        int ans=0;
        for(int i=0;i<tot;i++)
            ans+=sum[n/prime[i]]*2-1;
        cout<<ans<<endl;
    }
    return 0;
}