给定 N N N, M M M,求 1 ≤ x ≤ N 1 \leq x \leq N 1≤x≤N, 1 ≤ y ≤ M 1 \leq y \leq M 1≤y≤M 且 gcd ( x , y ) \gcd(x, y) gcd(x,y) 为质数的 ( x , y ) (x, y) (x,y) 有多少对。
推柿子:( n ≤ m n\leq m n≤m)
∑ 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=1n∑j=1m[gcd(i,j)=k] k∈prime
(常规操作,同除 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, k∈primen∑i=1⌊kn⌋∑j=1⌊km⌋[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, k∈primen∑i=1⌊kn⌋∑j=1⌊km⌋∑d∣gcd(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, k∈primen∑d=1⌊kn⌋μ(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=1n⌊Tn⌋×⌊Tm⌋∑k=1, k∈primenμ(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, k∈prime∑nμ(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——