Byteasar the Cryptographer works on breaking the code of BSA (Byteotian Security Agency). He has alreadyfound out that whilst deciphering a message he will have to answer multiple queries of the form"for givenintegers aa, bb and dd, find the number of integer pairs (x,y)(x,y) satisfying the following conditions:html
1\le x\le a1≤x≤a,1\le y\le b1≤y≤b,gcd(x,y)=dgcd(x,y)=d, where gcd(x,y)gcd(x,y) is the greatest common divisor of xx and yy".c++
Byteasar would like to automate his work, so he has asked for your help.优化
TaskWrite a programme which:spa
reads from the standard input a list of queries, which the Byteasar has to give answer to, calculates answers to the queries, writes the outcome to the standard output.code
FGD正在破解一段密码,他须要回答不少相似的问题:对于给定的整数a,b和d,有多少正整数对x,y,知足x<=a,y<=b,而且gcd(x,y)=d。做为FGD的同窗,FGD但愿获得你的帮助。orm
输入格式:htm
The first line of the standard input contains one integer nn (1\le n\le 50 0001≤n≤50 000),denoting the number of queries.blog
The following nn lines contain three integers each: aa, bb and dd(1\le d\le a,b\le 50 0001≤d≤a,b≤50 000), separated by single spaces.three
Each triplet denotes a single query.ip
输出格式:
Your programme should write nn lines to the standard output. The ii'th line should contain a single integer: theanswer to the ii'th query from the standard input.
输入样例#1:
2
4 5 2
6 4 3
输出样例#1:
3
2
预备知识:莫比乌斯反演,整除分块
不会的看这位dalao的博客莫比乌斯反演
本蒟蒻的整除分块
根据题意
\[ans=\sum_{i=1}^a \sum_{j=1}^b [{gcd(i,j)=d}]\]
\[ans=\sum_{i=1}^{a/d} \sum_{j=1}^{b/d}[gcd(i,j)=1]\]
下面就是反演
\[ans=\sum_{i=1}^{a/d} \sum_{j=1}^{b/d} \sum_{p|gcd(i,j)}\mu(p)\]
可是这样枚举仍是\(O(n^2)\),因此咱们换一个变量枚举,把最后一个求和提到前面,由于p既是i的因子又是j的因子,因此枚举范围就是\(min(a/d,b/d)\),那么继续推公式
\[ans=\sum_{p=1}^{min(a/d,b/d)}{\mu(p)} \sum_{i=1}^{a/d} \sum_{j=1}^{b/d} \lfloor\frac{a}{p\times d} \rfloor \lfloor\frac{b}{p\times d}\rfloor\]
若是对于后面的式子不理解,能够这么看,令\(x=a/d,y=b/d\)
\(p\)是\(x,y\)的一个因子,在\(x\)的范围内有\(\lfloor\frac{x}{p}\rfloor\)个\(p\)的倍数,对于\(y\)同理,因此每一个因子\(p\)都有\(\lfloor\frac{x}{p}\rfloor\lfloor\frac{y}{p}\rfloor\)的贡献
而对于后面的两个求和咱们是能够用前缀和预处理出来的,这个时候是能够作到\(O(n)\)了,可是因为多组数据,因此咱们发现,对于一段连续的p,由于a和b的值是肯定的,因此\(\lfloor\frac{a}{p\times d}\rfloor\lfloor\frac{b}{p\times d}\rfloor\)的值也是肯定的,这中间有许多重复的值,那么咱们就可使用整除分块优化到\(O(\sqrt n)\)
(有错误欢迎指出)
#include<bits/stdc++.h> #define lol long long #define il inline #define rg register #define Min(a,b) (a)<(b)?(a):(b) #define Max(a,b) (a)>(b)?(a):(b) using namespace std; const int N=5e4+10; void in(int &ans) { ans=0; int f=1; char i=getchar(); while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();} while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+i-'0', i=getchar(); ans*=f; } int n,m,d,tot,ans,T; int mu[N],sum[N],prime[N]; bool vis[N]; il void get_mu() { mu[1]=1; for(int i=2;i<=N-10;i++) { if(!vis[i]) prime[++tot]=i,mu[i]=-1; for(int j=1;j<=tot && prime[j]*i<=N-10;j++) { vis[i*prime[j]]=1; if(i%prime[j]==0) break; else mu[i*prime[j]]=-mu[i]; } } for(int i=1;i<=N-10;i++) sum[i]=sum[i-1]+mu[i]; } int main() { in(T); get_mu(); while(T--) { in(n),in(m),in(d); int nn=n/=d,mm=m/=d,ans=0; for(rg int i=1,pos,p=Min(n,m);i<=p;i=pos+1) { pos=Min(n/(n/i),m/(m/i)); ans+=(sum[pos]-sum[i-1])*(nn/i)*(mm/i); } printf("%d\n",ans); } return 0; }