【BZOJ 2818】 gcd(附φ的线性筛法预处理)

来源:互联网 发布:as3.0调用js页面方法 编辑:程序博客网 时间:2024/06/11 00:54

Description

给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的
数对(x,y)有多少对.
注意,若x!=y,则(x,y)与(y,x)都要计算在内。
1<=N<=10^7

Analysis

gcd(px,py)=p,p为素数。
满足上式的x,y必然互质。
因此

Ans=1pn,p(1+2x=2npφ(x))

预处理φ的前缀和,直接O(n)扫过。
但是,身为蒟蒻的我,太弱,竟然忘了φ的线筛预处理,赶紧恶补了一下。

φ的预处理

因为线筛只可能出现gcd(x,y)=1y|x的情况,所以我们只用对这两种情况讨论。
首先,因为φ是积性函数,所以若gcd(x,y)=1,则φ(xy)=φ(x)φ(y)
而若y|x,则φ(xy)=φ(x)y,证明如下:
正难则反,首先有一个神奇的性质。
n,m不互质,设其gcdb,则有n=k1b,m=k2b.
n+m=(k1+k2)b,亦不与nm互质。
[1,x]中与x不互质的数个数为xφ(x)个。
所以[x+1,x+x]中与x+x不互质的数的个数亦为xφ(x)个。

[1,xy]中与x不互质的数的个数为y(xφ(x))
即与x互质的数的个数就是yφ(x)

Code

#include<cstdio>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)using namespace std;typedef long long ll;const int N=int(1e7);int n,pri[N];ll ans,phi[N];bool bz[N];void pre(int n){    phi[1]=1;    fo(i,2,n)    {        if(!bz[i]) bz[i]=1,pri[++pri[0]]=i,phi[i]=i-1;        fo(j,1,pri[0])        {            int t=i*pri[j];            if(t>n) break;            bz[t]=1;            if(i%pri[j]==0)            {                phi[t]=phi[i]*pri[j];                break;            }            phi[t]=phi[i]*phi[pri[j]];        }    }    fo(i,3,n) phi[i]+=phi[i-1];}int main(){    scanf("%d",&n);    pre(n);    fo(i,1,pri[0])    {        if(n/pri[i]<2) break;        ans+=phi[n/pri[i]]*2;    }    printf("%lld",ans+pri[0]);    return 0;}
0 0
原创粉丝点击