题目链接
解题思路
到这里整个反演就结束了,由于是多组输入,因此应该预处理
μ
\mu
μ数组,并且预处理出从i=1到MAX_N的
∑
M
A
X
N
/
i
\sum MAXN/i
∑MAXN/i,存入sum数组。这样在计算的时候直接使用sum[n/d]就可以了。
AC代码
#include <iostream>
using namespace std;
typedef long long ll;
const int MAX_N = 50005;
long long sum[MAX_N], mu[MAX_N], prime[MAX_N];
bool vis[MAX_N];
void init()
{
mu[1] = 1;
int ans = 0;
for (int i=2; i<MAX_N; i++)
{
if (!vis[i])
{
prime[ans++] = i;
mu[i] = -1;
}
for (int j=0; j<ans&&i*prime[j]<MAX_N; j++)
{
vis[i*prime[j]] = 1;
if (i%prime[j] == 0)
{
mu[i*prime[j]] = 0;
break;
}
else
{
mu[i*prime[j]] = -mu[i];
}
}
mu[i]+=mu[i-1];
}
for (ll i=1; i<MAX_N; i++)
{
long long ans = 0;
for (ll l=1, r; l<=i; l=r+1)
{
r = i/(i/l);
ans = ans+(r-l+1)*(i/l);
}
sum[i] = ans;
}
}
int main()
{
int t;
init();
scanf("%d", &t);
while (t--)
{
ll n, m;
long long num = 0;
scanf("%lld %lld", &n, &m);
ll k = min(n, m);
for (ll l=1, r; l<=k; l=r+1)
{
r=min(n/(n/l), m/(m/l));
num+=(mu[r]-mu[l-1])*(sum[n/l])*(sum[m/l]);//因为分块,这一块的d值都是相同的,所以只需要乘上sum[n/l]即可
}
printf("%lld\n", num);
}
return 0;
}