题目链接: P4450 双亲数
题目大意: 我们以 d = g c d ( a , b ) d=gcd(a,b) d=gcd(a,b) 表示 a a a 和 b b b 的最大公约数,现已知 a ≤ A , b ≤ B a\leq A,b\leq B a≤A,b≤B 求满足 d = g c d ( a , b ) d=gcd(a,b) d=gcd(a,b) 的 a a a 和 b b b 有多少对。
题目分析: 我们设题目中要求的答案为
f
(
x
)
f(x)
f(x) ,
f
(
x
)
=
∑
i
=
1
A
∑
j
=
1
B
[
g
c
d
(
i
,
j
)
=
=
d
]
f(x)=\sum_{i=1}^A\sum_{j=1}^B[gcd(i,j)==d]
f(x)=i=1∑Aj=1∑B[gcd(i,j)==d]
另外设
g
(
x
)
=
∑
x
∣
d
f
(
d
)
g(x)=\sum_{x|d}f(d)
g(x)=x∣d∑f(d)将
A
A
A 和
B
B
B 同时除以
d
d
d 得
A
′
A'
A′ 和
B
′
B'
B′ ,则
f
(
x
)
f(x)
f(x) 可化为
f
(
x
)
=
∑
i
=
1
A
′
∑
j
=
1
B
′
[
g
c
d
(
i
,
j
)
=
=
1
]
f(x)=\sum_{i=1}^{A'}\sum_{j=1}^{B'}[gcd(i,j)==1]
f(x)=i=1∑A′j=1∑B′[gcd(i,j)==1]由
g
(
x
)
g(x)
g(x) 反演可以得出
f
(
x
)
=
∑
x
∣
d
μ
(
d
x
)
g
(
d
)
f(x)=\sum_{x|d}\mu(\frac{d}{x})g(d)
f(x)=x∣d∑μ(xd)g(d)当
x
=
1
x=1
x=1 时
f
(
1
)
=
∑
1
∣
d
μ
(
d
1
)
g
(
d
)
f(1)=\sum_{1|d}\mu(\frac{d}{1})g(d)
f(1)=1∣d∑μ(1d)g(d) 即
f
(
1
)
=
∑
i
=
1
n
μ
(
i
)
g
(
i
)
f(1)=\sum_{i=1}^{n}\mu(i)g(i)
f(1)=i=1∑nμ(i)g(i)而对于
g
(
x
)
g(x)
g(x) 将
f
(
x
)
f(x)
f(x) 带入可得
g
(
x
)
=
∑
x
∣
d
∑
i
=
1
A
∑
j
=
1
B
[
g
c
d
(
i
,
j
)
=
=
d
]
g(x)=\sum_{x|d}\sum_{i=1}^{A}\sum_{j=1}^{B}[gcd(i,j)==d]
g(x)=x∣d∑i=1∑Aj=1∑B[gcd(i,j)==d] 即
g
(
x
)
=
∑
i
=
1
A
∑
j
=
1
B
[
x
∣
g
c
d
(
i
,
j
)
]
g(x)=\sum_{i=1}^{A}\sum_{j=1}^{B}[x|gcd(i,j)]
g(x)=i=1∑Aj=1∑B[x∣gcd(i,j)]进一步变形
g
(
x
)
=
∑
i
=
1
⌊
A
x
⌋
∑
j
=
1
⌊
B
x
⌋
[
1
∣
g
c
d
(
i
,
j
)
]
g(x)=\sum_{i=1}^{\lfloor \frac{A}{x} \rfloor}\sum_{j=1}^{\lfloor \frac{B}{x} \rfloor}[1|gcd(i,j)]
g(x)=i=1∑⌊xA⌋j=1∑⌊xB⌋[1∣gcd(i,j)]
即
g
(
x
)
=
⌊
A
x
⌋
⌊
B
x
⌋
g(x)=\lfloor \frac{A}{x} \rfloor\lfloor \frac{B}{x} \rfloor
g(x)=⌊xA⌋⌊xB⌋
带回到
f
(
x
)
f(x)
f(x) 中
f
(
1
)
=
∑
i
=
1
A
⌊
A
x
⌋
⌊
B
x
⌋
μ
(
i
)
f(1)=\sum_{i=1}^A\lfloor \frac{A}{x} \rfloor\lfloor \frac{B}{x} \rfloor\mu(i)
f(1)=i=1∑A⌊xA⌋⌊xB⌋μ(i)最后只需要线性筛出
μ
(
i
)
\mu(i)
μ(i)即可。下面是完整代码:
题目代码:
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define mxn 1100000
#define LL long long
#define min(a,b)(a<b?a:b)
#define swap(a,b)(a+=b,b=a-b,a=a-b)
using namespace std;
LL mu[mxn],prime[mxn],used[mxn],cnt,sum[mxn];
inline void get_mu()
{
LL n=mxn;
mu[1]=1;
for(int i=2;i<=n;i++)
{
if(!used[i]){
prime[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt&&i*prime[j]<=n;++j)
{
used[i*prime[j]]=1;
if(i%prime[j]==0)break;
else mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+mu[i];
}
int main()
{
LL A,B,d;
LL ans;
get_mu();
scanf("%lld %lld %lld",&A,&B,&d);
A/=d;B/=d;
if(A>B)swap(A,B);
for(LL l=1,r;l<=A;l=r+1)
{
r=min(A/(A/l),B/(B/l));
ans+=(A/l)*(B/l)*(sum[r]-sum[l-1]);
}
printf("%lld\n",ans);
return 0;
}