HYSBZ - 2818 欧拉筛

https://www.lydsy.com/JudgeOnline/problem.php?id=2818

给定整数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)的结果为一个素数,我们不妨设该素数为p,那么Gcd(x/p,y/p)=1,也就是求在区间[1,n/p]内的互质的有序数对的数量,我们考虑欧拉函数φ(n)的定义就是小于n的且与n互质的正整数的个数,那么我们用一个前缀和数组来存储欧拉函数的和,在区间[1,n/p]的数量就是:sum[n/p]*2-1,减去1是因为(1,1)这一对算了两次。这只是一个素数p所贡献的数量,我们要统计在区间[1,n]的所有素数的贡献和。(有点绕 所以做这道题我也理解了好久才懂,举个例子说明吧)

phi[1](1,1)   
phi[2](1,2)   
phi[3](1,3)(2,3)  
phi[4](1,4)(3,4)  
phi[5](1,5)(2,5)(3,5)(4,5)

这样应该理解为什么要乘2减1了吧。 
 

#include<iostream>
#include<cstdio>
#include<stack>
#include<cmath>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<iterator>
#define INF 0x3f3f3f3f
#define EPS 1e-10
typedef long long ll;
typedef unsigned long long ull;
using namespace std;

int prime[10000005];
int flag[10000005];
ll phi[10000005];
ll sum[10000005];

int num=0;

void euler(int n);

int main()
{
	int n;
	scanf("%d",&n);
	euler(n);
	for(int i=1;i<=n;i++)
		sum[i]=sum[i-1]+phi[i];
	ll re=0;
	for(int i=1;i<=num;i++)
		re+=sum[n/prime[i]]*2-1;
	printf("%lld\n",re);
	return 0;
}

void euler(int n)
{
	phi[1]=1;//1要特判
	for (int i=2;i<=n;i++)
	{
		if (flag[i]==0)//这代表i是质数
		{
			prime[++num]=i;
			phi[i]=i-1;
		}
		for (int j=1;j<=num&&prime[j]*i<=n;j++)//经典的欧拉筛写法
		{
			flag[i*prime[j]]=1;//先把这个合数标记掉
			if (i%prime[j]==0)
			{
				phi[i*prime[j]]=phi[i]*prime[j];//若prime[j]是i的质因子,则根据计算公式,i已经
												//包括i*prime[j]的所有质因子
				break;//经典欧拉筛的核心语句,这样能保证每个数只会被自己最小的因子筛掉一次
			}
			else
				phi[i*prime[j]]=phi[i]*phi[prime[j]];//利用了欧拉函数是个积性函数的性质
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值