题意
(Tle 10^4) 次询问 (n,m) ,求
[sum _{i=1}^nsum _{j=1}^m[gcd(i,j) ext { is prime}]
]
分析
这题还是很有趣的。设 (nle m) 。
[egin{aligned}
sum _{i=1}^nsum_{j=1}^m[gcd(i,j) ext { is prime}]&=sum _{i=1}^nsum _{j=1}^msum _k [k ext { is prime}][gcd(i,j)=k] \
&=sum _{i=1}^nsum _{j=1}^msum _{k|i,k|j}[k ext { is prime}]sum _{d|frac{i}{k},d|frac{j}{k}}mu(d) \
&=sum _{d=1}^nmu (d)sum _{k=1}^n[k ext { is prime}]sum _{i=1}^{lfloorfrac{n}{k}
floor}sum _{j=1}^{lfloorfrac{m}{k}
floor}[d|i,d|j] \
&=sum _{d=1}^nmu (d)sum _{k=1}^n[k ext { is prime}]lfloorfrac{n}{kd}
floor lfloorfrac{m}{kd}
floor \
&=sum _{i=1}^nlfloorfrac{n}{i}
floor lfloorfrac{m}{i}
floorsum _{k|i,k ext { is prime}}mu(frac{i}{k})
end{aligned}
]
令 (f(x)=sum _{k|x,k ext {is prime }}mu (x/k)) ,我们有:
[ans=sum _{i=1}^nlfloorfrac{n}{i}
floorlfloorfrac{m}{i}
floor f(i)
]
(f(x)) 可以在线性筛的过程中顺便处理出来,求前缀和就可以做到每次询问 (O(sqrt n)) 。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long giant;
inline int read() {
int x=0,f=1;
char c=getchar_unlocked();
for (;!isdigit(c);c=getchar_unlocked()) if (c=='-') f=-1;
for (;isdigit(c);c=getchar_unlocked()) x=x*10+c-'0';
return x*f;
}
const int maxn=1e7+1;
bool np[maxn];
int p[maxn],ps=0,mu[maxn],f[maxn];
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
mu[1]=1,f[1]=0;
for (int i=2;i<maxn;++i) {
if (!np[i]) p[++ps]=i,mu[i]=-1,f[i]=1;
for (int j=1,tmp;j<=ps && (tmp=i*p[j])<maxn;++j) {
np[tmp]=true;
if (i%p[j]) mu[tmp]=-mu[i],f[tmp]=mu[i]-f[i]; else {
mu[tmp]=0;
f[tmp]=mu[i];
break;
}
}
}
for (int i=2;i<maxn;++i) f[i]+=f[i-1];
int T=read();
while (T--) {
int n=read(),m=read();
if (n>m) swap(n,m);
giant ans=0;
for (int i=1,j;i<=n;i=j+1) {
j=min(n/(n/i),m/(m/i));
ans+=(giant)(f[j]-f[i-1])*(n/i)*(m/i);
}
printf("%lld
",ans);
}
return 0;
}