原题链接:https://www.luogu.org/problemnew/show/P3455
ZAP-Queries
题目描述
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:
1≤x≤a 1 ≤ x ≤ a , 1≤y≤b 1 ≤ y ≤ b , gcd(x,y)=d g c d ( x , y ) = d , where gcd(x,y) g c d ( x , y ) is the greatest common divisor of xx and yy “.
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 n(1≤n≤50 000) n ( 1 ≤ n ≤ 50 000 ) ,denoting the number of queries.
The following nn lines contain three integers each: a a , and d d ), separated by single spaces.
Each triplet denotes a single query.
输出格式:
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
题解
由题,我们可以得到最直观的式子:
那么,我们可以考虑提出式子里的 d d ,相当于缩小了我们枚举的范围,答案不变:
设 n=⌊ad⌋,m=⌊bd⌋ n = ⌊ a d ⌋ , m = ⌊ b d ⌋ ,代入上面的式子:
又因为有:
略微解释一下,因为莫比乌斯函数 μ(x) μ ( x ) 有如下性质:
所以上面的式子只有当 gcd(i,j)=1 g c d ( i , j ) = 1 时取值不为零,所以 gcd(i,j)=1 g c d ( i , j ) = 1 等价于 ∑k|gcd(i,j)μ(k) ∑ k | g c d ( i , j ) μ ( k ) 。
再次代入:
此时,我们不再先枚举 i,j i , j ,我们先枚举 gcd g c d 为 k k 的情况:
这时,后面两个 Σ Σ 的答案就是 i,j i , j 同时整除 k k 的情况,显然的,中,整除 k k 的数有个,同理, 1∼m 1 ∼ m 中有 ⌊mk⌋ ⌊ m k ⌋ 个整除 j j 的数。所以,后面两个的答案为 ⌊nk⌋⌊mk⌋ ⌊ n k ⌋ ⌊ m k ⌋ ,故式子最后化简为:
将 n,m n , m 回代,得到最终结果:
此时,我们已经可以在 O(n) O ( n ) 的复杂度内计算出答案了,但是存在多组询问,所以我们需要进一步降低单词询问复杂度。
我们发现,在一段区间 k∈[l,r] k ∈ [ l , r ] 中, ⌊adk⌋,⌊bdk⌋ ⌊ a d k ⌋ , ⌊ b d k ⌋ 的值是一样的,而这样的区间有大约 n−−√ n 个,这段 [l,r] [ l , r ] 中的 Σ Σ 就可以直接计算,所以我们只需要 n−−√ n 的复杂度就能算出一次询问,总复杂度为 O(qn−−√) O ( q n ) 。
代码
#include<bits/stdc++.h>
#define ll long long
#define R register int
using namespace std;
const int M=5e4+5,N=5e4;
int p[M],miu[M],n;
bool check[M];
void getmiu()
{
miu[1]=check[1]=1;
R i,j,t;
for(i=2;i<=N;++i)
{
if(!check[i])miu[i]=-1,p[++p[0]]=i;
for(j=1;j<=p[0];++j)
{
t=p[j]*i;
if(t>N)break;
check[t]=1;
if(i%p[j]==0){miu[t]=0;break;}
miu[t]=-miu[i];
}
miu[i]+=miu[i-1];
}
}
ll f(int a,int b,int d)
{
a/=d,b/=d;
ll ans=0;
if(a>b)swap(a,b);
for(int l=1,r;l<=a;l=r+1)
r=min(a/(a/l),b/(b/l)),ans+=1ll*(miu[r]-miu[l-1])*(a/l)*(b/l);
return ans;
}
void in(){getmiu();scanf("%d",&n);}
void ac(){R i,a,b,c;for(i=1;i<=n;++i)scanf("%d%d%d",&a,&b,&c),printf("%lld\n",f(a,b,c));}
int main()
{
in();ac();
return 0;
}