Description
神犇YY虐完数论后给傻×kAc出了一题给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对kAc这种
傻×必然不会了,于是向你来请教……多组输入
Input
第一行一个整数T 表述数据组数接下来T行,每行两个正整数,表示N, M
Output
T行,每行一个整数表示第i组数据的结果
Sample Input
2
10 10
100 100
Sample Output
30
2791
HINT
T = 10000
N, M <= 10000000
分析
设g(d)表示1<=x<=n,1<=y<=m中gcd(x,y)=d的数对数量
设f(d)表示1<=x<=n,1<=y<=m中d|gcd(x,y)的数对数量
显然 f(d)=∑d|ng(n)=⌊nd⌋∗⌊md⌋
反演得 g(d)=∑d|nf(n)μ(nd)
可得 g(1)=∑nd=1μ(nd)⌊nd⌋⌊md⌋
设n<=m
那么 ans=∑np为质数∑nd=1μ(d)⌊npd⌋⌊mpd⌋
设 T=pd
则式子可化简为 ans=∑nT=1⌊nT⌋⌊mT⌋∑p|T且p为质数μ(Tp)
枚举每个质数处理处 ∑p|T且p为质数μ(Tp) 的前缀和然后分块直接上分块大法即可。
记得开long long
代码
#include <bits/stdc++.h>
#define N 10000005
#define ll long long
int mu[N],notPrime[N],prime[N];
int s[N];
ll ans;
int n,m;
int tot;
void getMu()
{
mu[1] = 1;
for (int i = 2; i <= N; i++)
{
if (!notPrime[i])
{
prime[++tot] = i;
mu[i] = -1;
}
for (int j = 1; j <= tot && i * prime[j] <= N; j++)
{
notPrime[i * prime[j]] = 1;
if (i % prime[j] == 0)
{
mu[i * prime[j]] = 0;
break;
}
mu [i * prime[j]] = -mu[i];
}
}
for (int i = 1; i <= tot; i++)
for (int j = prime[i]; j <= N; j += prime[i])
s[j] += mu[j / prime[i]];
for (int i = 1; i <= N; i++)
s[i] += s[i - 1];
}
void slove()
{
int last;
for (int i = 1; i <= n; i = last + 1)
{
last = std::min(n / (n / i),m / (m / i));
ans += (ll) (n / i) * (m / i) * (s[last] - s[i - 1]);
}
}
int main()
{
int T;
getMu();
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);
if (n > m)
std::swap(n,m);
ans = 0;
slove();
printf("%lld\n",ans);
}
}