bzoj2818

探讨了如何高效计算给定整数N范围内,所有GCD为素数的数对(x,y)的数量。通过枚举质数并利用欧拉函数优化算法,实现了接近线性的复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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(i,j)=p的对数(1<=i<=n,1<=j<=n),那么我们完全可以把n/p,然后就gcd(i,j)=1的对数,对于每个p,答案极为mu(k)*[n/k]^2,由于n/k只有根号n种取值,所以对于每个p可以用根号n的时间求出对应的答案,那么枚举p的效率是n/ln(n),那么这样的复杂度就是n^1.5/ln(n),然后我们发现n/p的数的种类是根号级别的所以这题复杂度就是O(n)。


#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 10000005;
int mu[MAXN], prim[MAXN / 10], cnt;
bool f[MAXN];
int i, n, m, j, k, l;
long long ans;
inline long long getans(int n)
{
	long long tot = 0;
	for(int i = 1; i <= n;)
	{
		int j = n / i;
		int y = n / j, x = i;
		if (x > y) swap(x, y);
		tot += (mu[y] - mu[x - 1]) * j * (long long)j;
		i = y + 1;
	}
	return tot;
}
int main()
{
	mu[1] = 1;
	cin >> n;
	for(i = 2; i <= n; i ++)
	{
		if (!f[i])
		{
			prim[++cnt] = i;
			mu[i] = -1;
		}
		for(j = 1; j <= cnt && prim[j] * i <= n; j ++)
		{
			f[i * prim[j]] = 1;
			if (i % prim[j]) mu[i * prim[j]] = -mu[i];
			else {mu[i * prim[j]] = 0; break;}
		}
	}
	for(i = 2; i <= n; i ++)
		mu[i] += mu[i - 1];
	int p = 1;
	for(i = 1; i <= cnt; i ++)
	{
		if (i != cnt && n / prim[i] == n / prim[i + 1]) p ++;
		else ans += p * getans(n / prim[i]), p = 1;
	}
	cout << ans << endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值