题目描述
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 aaa, bbb and ddd, find the number of integer pairs (x,y)(x,y)(x,y) satisfying the following conditions:
1≤x≤a1le xle a1≤x≤a,1≤y≤b1le yle b1≤y≤b,gcd(x,y)=dgcd(x,y)=dgcd(x,y)=d, where gcd(x,y)gcd(x,y)gcd(x,y) is the greatest common divisor of xxx and yyy".
Byteasar would like to automate his work, so he has asked for your help.
TaskWrite a programme which:
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.
FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d。作为FGD的同学,FGD希望得到你的帮助。
输入输出格式
输入格式:The first line of the standard input contains one integer nnn (1≤n≤50 0001le nle 50 0001≤n≤50 000),denoting the number of queries.
The following nnn lines contain three integers each: aaa, bbb and ddd(1≤d≤a,b≤50 0001le dle a,ble 50 0001≤d≤a,b≤50 000), separated by single spaces.
Each triplet denotes a single query.
输出格式:Your programme should write nnn lines to the standard output. The iii'th line should contain a single integer: theanswer to the iii'th query from the standard input.
输入输出样例
2
4 5 2
6 4 3
3
2
Solution:
本题莫比乌斯反演板子题。
题意就是求$sum_limits{i=1}^{ileq n}sum_limits{j=1}^{jleq m} gcd(i,j)==d$。
令$f(n)$表示满足约束条件的且$gcd(i,j)=n$的个数,令$F(n)$表示满足约束条件的且$n|gcd(i,j)$的个数。
于是有$F(n)=sum_limits{n|d} {f(d)}$,这个式子显然可以反演,得到$f(n)=sum_limits{n|d} {mu(frac{d}{n})*F(d)}$。
又因为对于数$x$,显然$n$中含有$frac{n}{x}$个$x$的倍数,同理$m$中有$frac{m}{x}$个,所以$F(x)=frac{n}{x}*frac{m}{x}$。
则原式变为$f(d)=sum_limits{d|k}^{kleq min(n,m)}{mu(frac{k}{d})frac{n}{k}frac{m}{k}}$。
令$t=frac{k}{d}$,则原式变为$f(d)=sum_limits{t=1}^{frac{min(n,m)}{d}}{frac{n}{td}frac{m}{td}}$,对于$lfloor frac{n}{td} floor lfloor frac{m}{td} floor$直接数论分块求就好了,所以还得预处理下$mu$的前缀和。
时间复杂度$O(qsqrt n)$。
代码:
/*Code by 520 -- 9.10*/ #include<bits/stdc++.h> #define il inline #define ll long long #define RE register #define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++) #define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--) using namespace std; const int N=50005; int n,a,b,d,mu[N],prime[N],cnt; bool isprime[N]; int gi(){ int a=0;char x=getchar(); while(x<'0'||x>'9')x=getchar(); while(x>='0'&&x<='9')a=(a<<3)+(a<<1)+(x^48),x=getchar(); return a; } il void pre(){ mu[1]=1; For(i,2,50000){ if(!isprime[i]) mu[i]=-1,prime[++cnt]=i; for(RE int j=1;j<=cnt&&prime[j]*i<=50000;j++){ isprime[i*prime[j]]=1; if(i%prime[j]==0) break; mu[i*prime[j]]=-mu[i]; } } For(i,1,50000) mu[i]+=mu[i-1]; } int solve(){ if(a>b) swap(a,b); a/=d,b/=d; int pos=0,ans=0; for(int i=1;i<=a;i=pos+1){ pos=min(a/(a/i),b/(b/i)); ans+=(mu[pos]-mu[i-1])*(a/i)*(b/i); } return ans; } int main(){ pre(); n=gi(); while(n--){ a=gi(),b=gi(),d=gi(); printf("%d ",solve()); } return 0; }