[Luogu P2257] [BZOJ 2820] YY的GCD

本文详细解析洛谷和BZOJ上一道关于质数对的计数问题,通过数学推导简化原式,利用筛法预处理函数G(x),结合底分块技巧实现高效求解。

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

洛谷传送门
BZOJ传送门

题目描述

神犇YY虐完数论后给傻×kAc出了一题

给定 N , M N, M N,M,求 1 ≤ x ≤ N , 1 ≤ y ≤ M 1\le x\le N, 1\le y\le M 1xN,1yM g c d ( x , y ) gcd(x, y) gcd(x,y)为质数的 ( x , y ) (x, y) (x,y)有多少对

kAc这种傻×必然不会了,于是向你来请教……

多组输入

输入输出格式

输入格式:

第一行一个整数 T T T 表述数据组数

接下来 T T T行,每行两个正整数,表示 N , M N, M N,M

输出格式:

T T T行,每行一个整数表示第i组数据的结果

输入输出样例

输入样例#1:
2
10 10
100 100
输出样例#1:
30
2791

说明

T = 10000 T = 10000 T=10000

N , M ≤ 10000000 N, M \le 10000000 N,M10000000

解题分析

先简化式子:(仍然不妨设 n ≤ m n \le m nm
∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) ∈ p r i m e ] = ∑ p ≤ n , p ∈ p r i m e ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = p ] = ∑ p ≤ n , p ∈ p r i m e ∑ i = 1 ⌊ n p ⌋ ∑ j = 1 ⌊ m p ⌋ ∑ d ∣ g c d ( i , j ) μ ( d ) = ∑ p ≤ n , p ∈ p r i m e ∑ d = 1 ⌊ n p ⌋ μ ( d ) ⌊ n d p ⌋ ⌊ m d p ⌋ \sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)\in prime] \\ =\sum_{p\le n,p\in prime}\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)=p] \\ =\sum_{p\le n,p\in prime}\sum_{i=1}^{\lfloor\frac{n}{p}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{p}\rfloor}\sum_{d|gcd(i,j)}\mu(d) \\ =\sum_{p\le n,p\in prime}\sum_{d=1}^{\lfloor\frac{n}{p}\rfloor}\mu(d)\lfloor\frac{n}{dp}\rfloor\lfloor\frac{m}{dp}\rfloor i=1nj=1m[gcd(i,j)prime]=pn,pprimei=1nj=1m[gcd(i,j)=p]=pn,pprimei=1pnj=1pmdgcd(i,j)μ(d)=pn,pprimed=1pnμ(d)dpndpm
T = d p T=dp T=dp
∑ p ≤ n , p ∈ p r i m e ∑ d = 1 ⌊ n p ⌋ μ ( d ) ⌊ n d p ⌋ ⌊ m d p ⌋ = ∑ T = 1 n ⌊ n T ⌋ ⌊ m T ⌋ ∑ d ∣ T μ ( d ) [ T d ∈ p r i m e ] \sum_{p\le n,p\in prime}\sum_{d=1}^{\lfloor\frac{n}{p}\rfloor}\mu(d)\lfloor\frac{n}{dp}\rfloor\lfloor\frac{m}{dp}\rfloor \\= \sum_{T=1}^{n}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{d|T}\mu(d)[\frac{T}{d}\in prime] pn,pprimed=1pnμ(d)dpndpm=T=1nTnTmdTμ(d)[dTprime]
G ( x ) = ∑ d ∣ x μ ( d ) [ x d ∈ p r i m e ] G(x)=\sum_{d|x}\mu(d)[\frac{x}{d}\in prime] G(x)=dxμ(d)[dxprime], x = p × q , p ∈ p r i m e x=p\times q, p\in prime x=p×q,pprime, 考虑如何筛这个玩意。

  • x x x为质数, G ( x ) = 1 G(x)=1 G(x)=1
  • 新加入的一个质数 p p p在原来的 q q q中间出现过了, 即 q   m o d   p = 0 q\ mod\ p=0 q mod p=0, 那么只有当 x d = p \frac{x}{d}=p dx=p的时候可能有值, 所以 G ( x ) = μ ( q ) G(x)=\mu (q) G(x)=μ(q)
  • 新加入的一个质数 p p p在原来的 q q q中间没有出现, 那么当 p ∣ d p|d pd的时候, 得到的值为 − G ( q ) -G(q) G(q), 当 x d = p \frac{x}{d}=p dx=p的时候, 得到的值为 μ ( q ) \mu(q) μ(q), 所以 G ( x ) = − G ( q ) + μ ( q ) G(x)=-G(q)+\mu(q) G(x)=G(q)+μ(q)

这样我们就可以线筛 G ( x ) G(x) G(x)了, 结合下底分块即可 A C AC AC

代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 10000050
template <class T>
IN void in(T &x)
{
	x = 0; R char c = gc;
	for (; !isdigit(c); c = gc);
	for (;  isdigit(c); c = gc)
	x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
int pcnt;
int pri[MX], F[MX], sum[MX], miu[MX];
bool npr[MX];
IN void get()
{
	F[1] = 0, miu[1] = 1;
	R int i, j, tar;
	for (i = 2; i <= 1e7; ++i)
	{
		if (!npr[i]) pri[++pcnt] = i, miu[i] = -1, F[i] = 1;
		for (j = 1; j <= pcnt; ++j)
		{
			tar = i * pri[j];
			if (tar > 1e7) break;
			npr[tar] = true;
			if (!(i % pri[j]))
			{
				F[tar] = miu[i];
				miu[tar] = 0;
				break;
			}
			miu[tar] = -miu[i];
			F[tar] = miu[i] - F[i];
		}
	}
	for (R int i = 1; i <= 1e7; ++i) sum[i] = sum[i - 1] + F[i];
}
int main(void)
{
	int T, n, m;
	R int lef, rig;
	long long ans;
	in(T); get();
	W (T--)
	{
		in(n), in(m); ans = 0;
		if (n > m) std::swap(n, m);
		lef = 1; 
		for (; lef <= n; lef = rig + 1)
		{
			rig = min(n / (n / lef), m / (m / lef));
			ans += 1ll * (sum[rig] - sum[lef - 1]) * (n / lef) * (m / lef);
		}
		printf("%lld\n", ans);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值