您的位置:首页 > 其它

【BZOJ 2818】Gcd - 筛法求素数&phi()

2016-03-12 13:28 411 查看

题目描述

给定整数NN,求1≤x,y≤N1\leq x,y\leq N且gcd(x,y)\gcd(x,y)为素数的数对(x,y)(x,y)有多少对.

1≤N≤1071\leq N\leq 10^7

分析

首先筛出所有的素数。

我们考虑枚举素数p,统计满足gcd(x,y)=p\gcd(x,y)=p的个数,等价于统计gcd(xp,yp)=1\gcd({x\over p},{y\over p})=1的个数,即统计[1,Np][1,{N\over p}]以内满足互质的有序数对个数dN/pd_{N/p}。

不难发现d1=1,di=di−1+2∗ϕ(i)d_1=1,d_i=d_{i-1}+2*\phi(i),也就是说,我们只要预处理出欧拉函数ϕ\phi,就可以在O(n)O(n)之内求出dd。

我们只需要用线性筛预处理出素数和欧拉函数,然后求dd,就可以在O(n)O(n)内解决问题。

代码

#include <cstdio>

typedef long long lint;

const int N=10000010;

int n;

int vis
;
int pri
;
int phi
;

lint d
;

lint res;

int main(void)
{
scanf("%d",&n);

vis[0]=vis[1]=1,phi[1]=1;
for (int i=2;i<=n;i++)
{
if (!vis[i]) pri[++pri[0]]=i,phi[i]=i-1;
for (int j=1;j<=pri[0];j++)
{
if ((lint)i*pri[j]>n) break;
vis[i*pri[j]]=1;
if (i%pri[j])
phi[i*pri[j]]=phi[i]*phi[pri[j]];
else phi[i*pri[j]]=phi[i]*pri[j];
if (i%pri[j]==0) break;
}
}

d[1]=1;
for (int i=2;i<=n;i++)
d[i]=d[i-1]+phi[i]*2;

for (int i=1;i<=pri[0];i++)
res=res+d[n/pri[i]];
printf("%lld\n",res);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: