题目大意:
$q(qleq50000)$组询问,对于给定的$n,m(n,mleq50000)$,求$displaystylesum_{i=1}^nsum_{j=1}^m au(ij)$。
思路:
$displaystyle au(ij)=sum_{x|i}sum_{y|j}[gcd(x,y)==1]$。
$$
egin{align*}
原式&=sum_{i=1}^nsum_{j=1}^msum_{x|i}sum_{y|j}[gcd(x,y)==1]\
&=sum_{i=1}^nsum_{j=1}^msum_{x|i}sum_{y|j}sum_{d|gcd(x,y)}mu(d)\
&=sum_{i=1}^nsum_{j=1}^msum_{d|gcd(i,j)}mu(d) au(frac id) au(frac jd)\
&=sum_{d=1}^{min(n,m)}sum_{i=1}^{lfloorfrac nd
floor} au(i)sum_{j=1}^{lfloorfrac md
floor} au(j)
end{align*}
$$
其中$sum au(i)$可以线性筛预处理,$d$可以数论分块枚举,单次询问复杂度$O(sqrt n)$。
1 #include<cstdio> 2 #include<cctype> 3 #include<algorithm> 4 typedef long long int64; 5 inline int getint() { 6 register char ch; 7 while(!isdigit(ch=getchar())); 8 register int x=ch^'0'; 9 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 10 return x; 11 } 12 const int N=50001,M=5134; 13 bool vis[N]; 14 int p[M],mu[N],tau[N],cnt[N],sum_mu[N],sum_tau[N]; 15 inline void sieve() { 16 mu[1]=tau[1]=sum_mu[1]=sum_tau[1]=1; 17 for(register int i=2;i<N;i++) { 18 if(!vis[i]) { 19 p[++p[0]]=i; 20 mu[i]=-1; 21 cnt[i]=1; 22 tau[i]=2; 23 } 24 for(register int j=1;j<=p[0]&&i*p[j]<N;j++) { 25 vis[i*p[j]]=true; 26 if(i%p[j]==0) { 27 mu[i*p[j]]=0; 28 cnt[i*p[j]]=cnt[i]+1; 29 tau[i*p[j]]=tau[i]/cnt[i*p[j]]*(cnt[i*p[j]]+1); 30 break; 31 } 32 mu[i*p[j]]=-mu[i]; 33 cnt[i*p[j]]=1; 34 tau[i*p[j]]=tau[i]*2; 35 } 36 sum_mu[i]=sum_mu[i-1]+mu[i]; 37 sum_tau[i]=sum_tau[i-1]+tau[i]; 38 } 39 } 40 int main() { 41 sieve(); 42 for(register int T=getint();T;T--) { 43 const int n=getint(),m=getint(),lim=std::min(n,m); 44 int64 ans=0; 45 for(register int l=1,r;l<=lim;l=r+1) { 46 r=std::min(n/(n/l),m/(m/l)); 47 ans+=(int64)(sum_mu[r]-sum_mu[l-1])*sum_tau[n/l]*sum_tau[m/l]; 48 } 49 printf("%lld ",ans); 50 } 51 return 0; 52 }