Description
FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a
,y<=b,并且gcd(x,y)=d。作为FGD的同学,FGD希望得到你的帮助。
Input
第一行包含一个正整数n,表示一共有n组询问。(1<=n<= 50000)接下来n行,每行表示一个询问,每行三个
正整数,分别为a,b,d。(1<=d<=a,b<=50000)
Output
对于每组询问,输出到输出文件zap.out一个正整数,表示满足条件的整数对数。
Sample Input
4 5 2
6 4 3
Sample Output
2
解题思路:
${sum_{i=1}^{n}}{sum_{j=1}^{m}}gcd(i,j)==d$
$={sum_{d|i}^{n}}{sum_{d|j}^{m}}varepsilon(gcd(frac{i}{d},frac{j}{d}))$
设${M={left lfloor {frac{m}{d}} ight floor}},{N={left lfloor {frac{n}{d}} ight floor}}$
$原式={sum_{i=1}^{N}}{sum_{j=1}^{M}}varepsilon(gcd(i,j))$
$={sum_{i=1}^{N}}{sum_{j=1}^{M}}{sum_{d|gcd(i,j)}}{mu (d)}$
$={sum_{d=1}^{min(N,M)}}{sum_{d|i}^{N}}{sum_{d|j}^{M}}{mu(d)}$
$={sum_{d=1}^{min(N,M)}}{mu(d)}{sum_{d|i}^{N}}1{sum_{d|j}^{M}}1$
$={sum_{d=1}^{min(N,M)}}{mu(d)}{sum_{i=1}^{left lfloor {frac{N}{d}} ight floor}}1{sum_{j=1}^{leftlfloor{frac{M}{d}} ight floor}}1$
$={sum_{d=1}^{min(N,M)}}{mu(d)}{leftlfloor{frac{N}{d}} ight floor}{leftlfloor{frac{M}{d}} ight floor}$
最后整除分块预处理$mu$的前缀和搞一下就好了
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 const int N=50010; 5 int prime[N]; 6 int miu[N]; 7 int s[N]; 8 bool vis[N]; 9 int cnt; 10 int T; 11 int a,b,d; 12 void gtp(void) 13 { 14 miu[1]=1; 15 for(int i=2;i<N;i++) 16 { 17 if(!vis[i]) 18 { 19 prime[++cnt]=i; 20 miu[i]=-1; 21 } 22 for(int j=1;j<=cnt&&prime[j]*i<N;j++) 23 { 24 vis[prime[j]*i]=true; 25 if(i%prime[j]==0) 26 { 27 miu[i*prime[j]]=0; 28 break; 29 } 30 miu[prime[j]*i]=-miu[i]; 31 } 32 } 33 for(int i=1;i<N;i++) 34 s[i]=s[i-1]+miu[i]; 35 return ; 36 } 37 int main() 38 { 39 gtp(); 40 scanf("%d",&T); 41 while(T--) 42 { 43 scanf("%d%d%d",&a,&b,&d); 44 a=a/d; 45 b=b/d; 46 int c=std::min(a,b); 47 int ans=0; 48 for(int k=1,u;k<=c;k=u+1) 49 { 50 u=std::min(a/(a/k),b/(b/k)); 51 ans+=(s[u]-s[k-1])*(a/k)*(b/k); 52 } 53 printf("%d ",ans); 54 } 55 return 0; 56 }