【题目】
Description
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) (x,y) satisfying the following conditions:
1 ≤ x ≤ a 1\le x\le a 1≤x≤a, 1 ≤ y ≤ b 1\le y\le b 1≤y≤b, g c d ( x , y ) = d gcd(x,y)=d gcd(x,y)=d, where g c d ( x , y ) gcd(x,y) gcd(x,y) is the greatest common divisor of x x x and y y y".
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.
Input
The first line of the standard input contains one integer n n n ( 1 ≤ n ≤ 50000 1\le n\le 50000 1≤n≤50000),denoting the number of queries.
The following nn lines contain three integers each: a a a, b b b and d d d( 1 ≤ d ≤ a , b ≤ 50000 1\le d\le a,b\le 50000 1≤d≤a,b≤50000), separated by single spaces.
Each triplet denotes a single query.
Output
Your programme should write nn lines to the standard output. The i’th line should contain a single integer: theanswer to the i’th query from the standard input.
Sample Input
2
4 5 2
6 4 3
Sample Output
3
2
【分析】
题目大意:有 n n n 组询问,每次给出 a , b , d a,b,d a,b,d,求出有多少对 ( x , y ) (x,y) (x,y) 满足 1 ≤ x ≤ a 1\le x\le a 1≤x≤a, 1 ≤ y ≤ b 1\le y\le b 1≤y≤b 且 gcd ( x , y ) = d \gcd(x,y)=d gcd(x,y)=d。
题目中实际上就是要我们求出 ∑ i = 1 a ∑ j = 1 b [    gcd ( i , j ) = d    ] \sum_{i=1}^a\sum_{j=1}^b[\;\gcd(i,j)=d\;] i=1∑aj=1∑b[gcd(i,j)=d]把它化个简就是 ∑ i = 1 ⌊ a d ⌋ ∑ j = 1 ⌊ b d ⌋ [    gcd ( i , j ) = 1    ] \sum_{i=1}^{\lfloor\frac{a}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{b}{d}\rfloor}[\;\gcd(i,j)=1\;] i=1∑⌊da⌋j=1∑⌊db⌋[gcd(i,j)=1]
我们定义(以下式子中
a
′
a'
a′ 代表
⌊
a
d
⌋
\lfloor\frac{a}{d}\rfloor
⌊da⌋,
b
′
b'
b′ 代表
⌊
b
d
⌋
\lfloor\frac{b}{d}\rfloor
⌊db⌋)
f
(
n
)
=
∑
i
=
1
a
′
∑
j
=
1
b
′
[
  
gcd
(
i
,
j
)
=
n
  
]
f(n)=\sum_{i=1}^{a'}\sum_{j=1}^{b'}[\;\gcd(i,j)=n\;]
f(n)=i=1∑a′j=1∑b′[gcd(i,j)=n]
F
(
n
)
=
∑
n
∣
k
m
i
n
(
a
′
,
b
′
)
f
(
k
)
F(n)=\sum_{n|k}^{min(a',b')}f(k)
F(n)=n∣k∑min(a′,b′)f(k)
不难发现的是
F
(
n
)
=
⌊
a
′
n
⌋
⌊
b
′
n
⌋
F(n)=\lfloor \frac{a'}{n}\rfloor\lfloor \frac{b '}{n}\rfloor
F(n)=⌊na′⌋⌊nb′⌋
那么用莫比乌斯反演得到
f ( n ) = ∑ n ∣ k m i n ( a ′ , b ′ ) F ( k ) μ ( k n ) = ∑ n ∣ k m i n ( a ′ , b ′ ) μ ( k n ) ⌊ a ′ k ⌋ ⌊ b ′ k ⌋ f(n)=\sum_{n|k}^{min(a',b')}F(k)\mu(\frac{k}{n})=\sum_{n|k}^{min(a',b')}\mu(\frac{k}{n})\lfloor \frac{a'}{k}\rfloor\lfloor \frac{b '}{k}\rfloor f(n)=n∣k∑min(a′,b′)F(k)μ(nk)=n∣k∑min(a′,b′)μ(nk)⌊ka′⌋⌊kb′⌋
根据 f ( n ) f(n) f(n) 的定义不难发现答案就是 f ( 1 ) f(1) f(1),也就是
f ( 1 ) = ∑ k = 1 m i n ( a ′ , b ′ ) μ ( k ) ⌊ a ′ k ⌋ ⌊ b ′ k ⌋ f(1)=\sum_{k=1}^{min(a',b')}\mu(k)\lfloor \frac{a'}{k}\rfloor\lfloor \frac{b '}{k}\rfloor f(1)=k=1∑min(a′,b′)μ(k)⌊ka′⌋⌊kb′⌋
那么先统计出 μ \mu μ 函数的前缀和,再进行整除分块就可以解决这道题了。
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 50005
#define Mod 998244353
using namespace std;
int prime[N],mu[N];
bool mark[N];
void linear_sieves()
{
int i,j,sum=0;
memset(mark,true,sizeof(mark));
mark[0]=mark[1]=false,mu[1]=1;
for(i=2;i<N;++i)
{
if(mark[i]) prime[++sum]=i,mu[i]=-1;
for(j=1;j<=sum&&i*prime[j]<N;++j)
{
mark[i*prime[j]]=false;
if(i%prime[j]) mu[i*prime[j]]=-mu[i];
else break;
}
}
for(i=1;i<N;++i) mu[i]+=mu[i-1];
}
int solve(int a,int b,int d)
{
a/=d,b/=d;
int i,j,ans=0;
if(a>b) swap(a,b);
for(i=1;i<=a;i=j+1)
{
j=min(a/(a/i),b/(b/i));
ans+=(mu[j]-mu[i-1])*(a/i)*(b/i);
}
return ans;
}
int main()
{
int n,i,a,b,d;
scanf("%d",&n);
linear_sieves();
for(i=1;i<=n;++i)
{
scanf("%d%d%d",&a,&b,&d);
printf("%d\n",solve(a,b,d));
}
return 0;
}