这道题与Problem b是非常相似的,只不过不是求一个固定的数,是求素数。
那么我们可以得到:
Ans=∑k∑⌊nk⌋d=1μ(d)⌊nk×d⌋⌊mk×d⌋
,其中
k
为
为表述方便,不妨令
T=k×d
,可以发现在求解的过程中,每次枚举到
T
的质因子,就要计算
Ans=∑nT=1⌊nT⌋⌊mT⌋∑k∣Tμ(Tk)
,令
f(T)=∑k∣Tμ(Tk)
,那么
Ans=∑nT=1⌊nT⌋⌊mT⌋f(T)
,可以发现如果能求出
f(T)
,我们就可以分块辣!
那么现在就考虑怎样预处理
f(T)
。
设
T=px11×px22×...×pxnn
,设
S=px1−11×px22×...×pxnn
,那么计算
f(T)
分两种情况:
①若
x1=1
即
S mod p1≠0
时,
f(S)=∑ki=2μ(Spi),f(T)=∑ki=1μ(Tpi)=μ(Tp1)+∑ki=2μ(Tpi)=μ(S)+∑ki=2μ(Spi×p1)=μ(S)+∑ki=2μ(Spi)μ(p1)=μ(S)−f(S)
。
②若
x1>1
,即
S mod p1=0,μ(px11)=0,f(T)=∑ki=1μ(Tpi)=μ(Tp1)+∑ki=2μ(Tpi)=μ(S)+∑ki=2μ(Tpi×px11×px11)=μ(S)+∑ki=2μ(Tpi×px11)×μ(px11)=μ(S)
然后我们就可以愉快的进行线性筛+分块辣。
#include<iostream>
#include<cstdio>
#define MAXN 10000005
#define ll long long
using namespace std;
int prime[MAXN],mobius[MAXN],f[MAXN],sum[MAXN];
bool flag[MAXN];
inline int read()
{
int a=0,f=1; char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
return a*f;
}
inline void prepare()
{
mobius[1]=1;
for (int i=2;i<MAXN;i++)
{
if (!flag[i]) prime[++prime[0]]=i,mobius[i]=-1,f[i]=1;
for (int j=1;j<=prime[0]&&i*prime[j]<MAXN;j++)
{
flag[i*prime[j]]=1;
if (i%prime[j]==0)
{
mobius[i*prime[j]]=0;
f[i*prime[j]]=mobius[i];
break;
}
else mobius[i*prime[j]]=-mobius[i],f[i*prime[j]]=mobius[i]-f[i];
}
}
for (int i=1;i<MAXN;i++)
sum[i]=sum[i-1]+f[i];
}
int main()
{
prepare();
int testcase=read();
while (testcase--)
{
ll n=read(),m=read();
if (n>m) swap(n,m);
ll ans=0; int pos=0;
for (int i=1;i<=n;i=pos+1)
{
pos=min(n/(n/i),m/(m/i));
ans+=(sum[pos]-sum[i-1])*(n/i)*(m/i);
}
printf("%lld\n",ans);
}
return 0;
}