Description
回答T组询问,有多少组gcd(x,y)=d,x<=a, y<=b。T, a, b<=4e5。
Solution
显然对于gcd=d的,应该把a/d b/d,然后转为gcd=1计算
计算用莫比乌斯反演相信大家都会
关键是有T组询问n^2会T
于是有这样一个优化可以做到每次sqrt(n)
每一次是ret+=mu[i]*(n/i)*(m/i)
可是除法向下取整所以会导致很多i的(n/i)*(m/i)一样
具体来说,向下取整得到的结果一定是约数所以对于(n/i)最多2sqrt(n)种
那么(n/i)*(m/i)放一起也就4sqrt(n)种
这个序列一定是不上升的,所以考虑对所有的(n/i)*(m/i)视为一块相同的一起算
那么肯定要记录下mu[i]的前缀和
如何快速得到每一块的l和r?
每一块的r肯定要么n%i==0要么m%i==0
于是用pos=min(n/(n/i),m/(m/i)) 定位
当然pos+1就是下一块的l了
Code
1 #include2 #include 3 #include 4 using namespace std; 5 const int maxn=5e4+5; 6 7 int flag[maxn],prime[maxn],cnt; 8 int mu[maxn],sum[maxn]; 9 10 int getmu(){11 mu[1]=1;12 for(int i=2;i m) swap(n,m);33 for(int i=1;i<=n;i=pos+1){34 pos=min(n/(n/i),m/(m/i));35 ret+=(sum[pos]-sum[i-1])*(n/i)*(m/i);36 }37 return ret;38 }39 40 int main(){41 int T,a,b,d;42 scanf("%d",&T);43 getmu();44 45 while(T--){46 scanf("%d%d%d",&a,&b,&d);47 a/=d,b/=d;48 printf("%d\n",cal(a,b));49 }50 return 0;51 }