CF1967B2(%你赛搬题题解)
题。首先枚举 \(\gcd(a,b)=d\),令 \(A=\frac ad,B=\frac bd\)。
\[Ad+Bd|Bd^2\\
A+B|Bd
\]
此时 \(\gcd(A+B,B)=\gcd(A,B)=1\),所以
\[A+B|d
\]
考虑 \(\mathcal O(n\ln n)\) 直接枚举 \(A+B=s\):
\[\sum_d \sum_{s|d} \sum_{A=1}^{\lfloor\frac nd\rfloor} \sum_{B=1}^{\lfloor\frac md\rfloor}[\gcd(A,B)=1][A+B=s]
\]
然而后面没法 \(\mathcal O(1)\) 算。此时需要注意力。直觉上,本题的限制比 EZver 更严。实际上,有
\[A\le s\le d=\frac aA\\
A\le \sqrt a\le \sqrt n\\
\text{同理}\; B\le \sqrt m
\]
那么暴力枚举有序对 \((A,B)\),可以 \(\mathcal O(1)\) 求出最大的满足条件的 \(d\),求 \(\sum \frac{d_{\max}}s\) 即可。复杂度 \(\mathcal O(\sqrt{nm})\) 即 \(\mathcal O(n)\)。
#include <cstdio>
int min(int a,int b){return a<b?a:b;}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int main()
{
int T;scanf("%d",&T);while(T--){
int n,m,ans=0;scanf("%d%d",&n,&m);
for(int a=1;a*a<=n;++a) for(int b=1;b*b<=m;++b)
if(gcd(a,b)==1) ans+=min(n/a,m/b)/(a+b);
printf("%d\n",ans);
}
}