题目描述
给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对。
其中数据加强,N和M将近1000w。
题解
根据莫比乌斯反演公式,则一定有:
f ( i ) = ∑ d = 1 ⌊ n i ⌋ g ( i ∗ d )    ⟺    g ( i ) = ∑ d = 1 ⌊ n i ⌋ μ ( d ) ∗ f ( i ∗ d ) f(i)\ =\ \sum_{d=1}^{\lfloor \frac{n}{i}\rfloor}\ g(i*d)\iff g(i)\ =\ \sum_{d=1}^{\lfloor \frac{n}{i}\rfloor}μ(d)*f(i*d) f(i) = d=1∑⌊in⌋ g(i∗d)⟺g(i) = d=1∑⌊in⌋μ(d)∗f(i∗d)
我们对于所求的答案
a
n
s
ans
ans,有:
a
n
s
=
∑
i
g
(
i
)
=
∑
i
∑
d
=
1
⌊
n
i
⌋
μ
(
d
)
⌊
n
i
∗
d
⌋
⌊
m
i
∗
d
⌋
ans\ =\ \sum_i g(i)\ =\ \sum_i \sum_{d=1}^{\lfloor \frac{n}{i}\rfloor}μ(d)\lfloor \frac{n}{i*d} \rfloor \lfloor \frac{m}{i*d}\rfloor
ans = i∑g(i) = i∑d=1∑⌊in⌋μ(d)⌊i∗dn⌋⌊i∗dm⌋
然后再对这一个
a
n
s
ans
ans算式变形一下:用T来枚举这一份i*d,则有:
a
n
s
=
∑
T
⌊
n
T
⌋
⌊
m
T
⌋
∑
d
∣
T
μ
(
T
d
)
ans\ =\ \sum_T \lfloor \frac{n}{T} \rfloor \lfloor \frac{m}{T}\rfloor \sum_{d|T}μ(\frac{T}{d})
ans = T∑⌊Tn⌋⌊Tm⌋d∣T∑μ(dT).
我们另 t ( i ) = ∑ d ∣ T μ ( T d ) t(i)\ =\ \sum_{d|T}μ(\frac{T}{d}) t(i) = ∑d∣Tμ(dT),我们只要能够快速的求出T(i)就能够很快的得到答案。
我们可以在线性筛结束的时候求解这一个t(i),大致是这样的:
for (int i=1;i<=m;++i)
for (int j=1;prime[i]*j<=n;++j)
f[prime[i]*j] += Miu[j];
在这其中, i i i枚举的是每一个质数, j j j枚举的是每一个数中, i ∗ p r i m e j i*prime_j i∗primej中除去 p r i m e j prime_j primej的值。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 10000015;
int f[N];
int sum[N];
int Miu[N];
int vis[N];
int prime[N];
void Get_Miu(int n)
{
int m = 0;
Miu[1] = 1;
for (int i=2;i<=n;++i)
{
if (vis[i] == 0) prime[++m] = i, Miu[i] = -1;
for (int j=1;j<=m && i*prime[j]<=n;++j)
{
vis[i*prime[j]] = 1;
if (i%prime[j] == 0) break;
Miu[i*prime[j]] = -Miu[i];
}
}
for (int i=1;i<=m;++i)
for (int j=1;prime[i]*j<=n;++j)
f[prime[i]*j] += Miu[j];
return;
}
void Get_sum(int n)
{
for (int i=1;i<=n;++i)
sum[i] = sum[i-1]+f[i];
return;
}
void work(void)
{
int n,m,j;
long long ans = 0;
scanf("%d %d",&n,&m);
for (int i=1;i<=min(n,m);i=j+1)
{
j = min(n/(n/i),m/(m/i));
ans += (long long)(sum[j]-sum[i-1])*(n/i)*(m/i);
}
printf("%lld\n",ans);
return;
}
int main(void)
{
Get_Miu(N-10);
Get_sum(N-10);
int n;
cin>>n;
while (n -- ) work();
return 0;
}