把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【数论】BZOJ 2818 Gcd

传送门

这道题看起来是一道很水的数论题
实际上就是一道很水的数论题Σ( ° △ °

G c d ( x , y ) = p Gcd(x,y)=p Gcd(x,y)=p,则 G c d ( x / p , y / p ) = 1 Gcd(x/p,y/p)=1 Gcd(x/p,y/p)=1
所以我们枚举素数 p p p,求出 N / p N/p N/p以内的互质的数的对数,然后每一个 p p p之下的答案求和就是最终答案

而欧拉函数的意义就是这个数以内与它互质的数的个数,所以我们把 p h i [ 1 ] phi[1] phi[1] p h i [ N / p ] phi[N/p] phi[N/p]加起来就是 N / p N/p N/p以内的互质的数的对数,筛出来之后用个前缀和就可以了。

由于这个数对是有序的,每次我们*2再减1(1,1的情况)就可以了

另外学校OJ的要求高一些 所以把phi和前缀和数组合并到了一起,否则会MLE

#include<cstdio>
#define LL long long
#define MAXN 10000005
int n,pn,prime[MAXN];
bool vis[MAXN];
LL ans,phi[MAXN];
void sieve()
{
	phi[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!vis[i])
		{
			phi[i]=i-1;
			prime[++pn]=i;
		}
		for(int j=1;j<=pn&&i*prime[j]<=n;j++)
		{
			vis[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			else phi[i*prime[j]]=phi[i]*phi[prime[j]];
		}
	}
}
int main()
{
	scanf("%d",&n);
	sieve();
	for(int i=1;i<=n;i++)
		phi[i]=phi[i-1]+phi[i];
	for(int i=1;i<=pn;i++)
		ans+=phi[n/prime[i]]*2-1;
	printf("%lld\n",ans);
	return 0;
}
posted @ 2019-04-11 14:06  Starlight_Glimmer  阅读(8)  评论(0编辑  收藏  举报  来源
浏览器标题切换
浏览器标题切换end