【LG-P2257】 YY的GCD

P2257 YY的GCD

给定 N N N, M M M,求 1 ≤ x ≤ N 1 \leq x \leq N 1xN 1 ≤ y ≤ M 1 \leq y \leq M 1yM gcd ⁡ ( x , y ) \gcd(x, y) gcd(x,y) 为质数的 ( x , y ) (x, y) (x,y) 有多少对。


推柿子:( n ≤ m n\leq m nm

∑ i = 1 n ∑ j = 1 m [ gcd ⁡ ( i , j ) = k ]   k ∈ p r i m e \sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=k]\ k\in prime i=1nj=1m[gcd(i,j)=k] kprime

(常规操作,同除 k k k:)

= ∑ k = 1 ,   k ∈ p r i m e n ∑ i = 1 ⌊ n k ⌋ ∑ j = 1 ⌊ m k ⌋ [ gcd ⁡ ( i , j ) = 1 ] =\sum_{k=1,\ k\in prime}^n\sum_{i=1}^{\left\lfloor\frac{n}{k}\right\rfloor}\sum_{j=1}^{\left\lfloor\frac{m}{k}\right\rfloor}[\gcd(i,j)=1] =k=1, kprimeni=1knj=1km[gcd(i,j)=1]

(根据莫比乌斯函数的性质,有:)

= ∑ k = 2 ,   k ∈ p r i m e n ∑ i = 1 ⌊ n k ⌋ ∑ j = 1 ⌊ m k ⌋ ∑ d ∣ gcd ⁡ ( i , j ) μ ( d ) =\sum_{k=2,\ k\in prime}^n\sum_{i=1}^{\left\lfloor\frac{n}{k}\right\rfloor}\sum_{j=1}^{\left\lfloor\frac{m}{k}\right\rfloor}\sum_{d|\gcd(i,j)} \mu(d) =k=2, kprimeni=1knj=1kmdgcd(i,j)μ(d)

(因为 d d d 同为 i i i j j j 的因数,所以反过来枚举 d d d 的倍数,即直接计算其倍数的数量即可:)

= ∑ k = 1 ,   k ∈ p r i m e n ∑ d = 1 ⌊ n k ⌋ μ ( d ) × ⌊ n k d ⌋ × ⌊ m k d ⌋ =\sum_{k=1,\ k\in prime}^n\sum_{d=1}^{\left\lfloor\frac{n}{k}\right\rfloor} \mu(d) \times\left\lfloor\frac{n}{kd}\right\rfloor\times\left\lfloor\frac{m}{kd}\right\rfloor =k=1, kprimend=1knμ(d)×kdn×kdm

(此时设 T = k d T=kd T=kd,有:)

= ∑ T = 1 n ⌊ n T ⌋ × ⌊ m T ⌋ ∑ k = 1 ,   k ∈ p r i m e n μ ( T k ) =\sum_{T=1}^n\left\lfloor\frac{n}{T}\right\rfloor\times\left\lfloor\frac{m}{T}\right\rfloor\sum_{k=1,\ k\in prime}^n \mu(\frac{T}{k}) =T=1nTn×Tmk=1, kprimenμ(kT)


到这里之后,对于 μ \mu μ 的值可以线性筛出来,然后处理出一个数组 f i = ∑ k = 1 ,   k ∈ p r i m e n μ ( i k ) f_i=\sum\limits_{k=1,\ k\in prime}^n \mu(\frac{i}{k}) fi=k=1, kprimenμ(ki)

再求出 f f f 的前缀和,最后柿子的前半部分可以用数论分块做,二者结合即可。

CODE:

#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define maxn 10000005

int t, n, m;
ll mu[maxn + 5], tot, prm[maxn + 5]; 
ll f[maxn + 5], sum[maxn + 5];
bool vis[maxn + 5];

inline void pre()
{
	mu[1] = 1;
	for(int i = 2; i <= maxn; ++i)
	{
		if(!vis[i])
			prm[++tot] = i, mu[i] = -1, vis[i] = 1;
		for(int j = 1; j <= tot and i * prm[j] <= maxn; ++j)
		{
			vis[i * prm[j]] = 1;
			if(i % prm[j] == 0) break;
			mu[i * prm[j]] = mu[i] * mu[prm[j]];
		}
	}
	for(int i = 1; i <= maxn; ++i)
		for(int j = 1; j <= tot and i * prm[j] <= maxn; ++j)
			f[i * prm[j]] += mu[i];
	for(int i = 1; i <= maxn; ++i)
		sum[i] = sum[i - 1] + f[i];
}

inline ll slv(int a, int b)
{
	long long ans = 0;
	for(int l = 1, r; l <= a; l = r + 1)
	{
		r = min(a / (a / l), b / (b / l));
		ans += (long long)(sum[r] - sum[l - 1]) * (long long)(a / l) * (long long)(b / l);
	}
	return ans;
}

signed main()
{
	scanf("%d", &t);
	pre();
	while(t--)
	{
		scanf("%d %d", &n, &m);
		if(n > m) swap(n, m);
		printf("%lld\n", slv(n, m));
	}
	return 0;
}

—— E n d End End——

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值