题面
题解
明显地,这个QQ数可以用 μ mu μ 表示,于是询问就变成了这样:
∑
i
=
1
n
∑
d
∣
i
(
1
−
μ
(
d
)
2
)
=
∑
d
=
1
n
⌊
n
d
⌋
(
1
−
μ
(
d
)
2
)
egin{aligned} & sum_{i=1}^nsum_{d|i}left(1-mu(d)^2
ight)\ =& sum_{d=1}^nleftlfloorfrac{n}{d}
ight
floorleft(1-mu(d)^2
ight) end{aligned}
=i=1∑nd∣i∑(1−μ(d)2)d=1∑n⌊dn⌋(1−μ(d)2)
发现
⌊
n
d
⌋
lfloordfrac{n}{d}
floor
⌊dn⌋ 是可以整除分块的,但是
n
≤
1
0
9
nleq 10^9
n≤109 无法线性筛
μ
mu
μ。
考虑如何更快地求出 ∑ i = 1 n ( 1 − μ ( d ) 2 ) sumlimits_{i=1}^nleft(1-mu(d)^2 ight) i=1∑n(1−μ(d)2),也就是 1 ∼ n 1sim n 1∼n 中的QQ数个数。
但是有这么一个神奇的式子:
∑
i
=
1
n
(
1
−
μ
(
i
)
2
)
=
∑
x
=
2
n
−
μ
(
x
)
⌊
N
x
2
⌋
sum_{i=1}^nleft(1-mu(i)^2
ight)=sum_{x=2}^{sqrt n}-mu(x)lfloorfrac{N}{x^2}
floor
i=1∑n(1−μ(i)2)=x=2∑n−μ(x)⌊x2N⌋
证明:
首先,对于每一个QQ数 a a a,他肯定可以拆分成这种形式: a = x 2 y a=x^2 y a=x2y(其中 x x x 不是QQ数),也就是说,我们把每一个QQ数表示成一个非QQ数的平方再乘上一个数。
比如QQ数 2 4 × 3 3 × 5 2^4 imes 3^3 imes 5 24×33×5 可以拆分为 ( 2 × 3 ) 2 × … (2 imes 3)^2 imes dots (2×3)2×…( x = 2 × 3 x=2 imes 3 x=2×3)或者 2 2 × … 2^2 imes dots 22×…( x = 2 x=2 x=2)或者 3 2 × … 3^2 imes dots 32×…( x = 3 x=3 x=3)。
那么 ∑ x = 2 n − μ ( x ) ⌊ N x 2 ⌋ sumlimits_{x=2}^{sqrt n}-mu(x)lfloordfrac{N}{x^2} floor x=2∑n−μ(x)⌊x2N⌋ 就可以看成是枚举每一个 x x x,然后再枚举有多少个 a a a,然后再配上一个 − μ ( x ) -mu(x) −μ(x) 去重。(至于能去重的原因结合 μ mu μ 的定义以及这个式子想一想: ∑ i = 1 n ( − 1 ) i ( n i ) = − 1 sumlimits_{i=1}^n(-1)^idbinom{n}{i}=-1 i=1∑n(−1)i(in)=−1)
那么就能在 n sqrt n n 的时间内求出 ∑ i = 1 n ( 1 − μ ( d ) 2 ) sumlimits_{i=1}^nleft(1-mu(d)^2 ight) i=1∑n(1−μ(d)2) 了。
时间复杂度比较玄学,反正能过。
代码如下:
#include<bits/stdc++.h>
#define SN 32000
#define ll long long
using namespace std;
int ql,qr;
int cnt,prime[SN],mu[SN];
bool notprime[SN];
void init()
{
mu[1]=1;
for(int i=2;i<=31622;i++)
{
if(!notprime[i])
{
prime[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt&&i*prime[j]<=31622;j++)
{
notprime[i*prime[j]]=1;
if(!(i%prime[j])) break;
mu[i*prime[j]]=-mu[i];
}
}
}
int summu(int n)
{
ll ans=0;
for(int i=2;i*i<=n;i++)
ans-=mu[i]*(n/i/i);
return ans;
}
ll solve(int n)
{
ll ans=0;
for(int l=1,r,last=0;l<=n;l=r+1)
{
r=n/(n/l);
ll tmp=summu(r);
ans+=(n/l)*(tmp-last);
last=tmp;
}
return ans;
}
int main()
{
init();
scanf("%d%d",&ql,&qr);
printf("%lld
",solve(qr)-solve(ql-1));
return 0;
}