链接:http://www.51nod.com/Challenge/Problem.html#problemId=1742
要点:
1、这里的枚举变换和平时的不大一样?
2、莫比乌斯函数和容斥
根据莫比乌斯函数定义,我们得到要求的答案为:
a
n
s
=
∑
i
=
1
n
∑
d
∣
i
(
1
−
∣
μ
(
d
)
∣
)
ans=\sum_{i=1}^{n}\sum_{d|i}(1-|\mu(d)|)
ans=i=1∑nd∣i∑(1−∣μ(d)∣)
这里我们这里我们令t=i/d,则:变换为:
a
n
s
=
∑
t
=
1
n
∑
d
=
1
n
t
(
1
−
∣
μ
(
d
)
∣
)
=
∑
t
=
1
n
F
(
n
t
)
\begin{aligned} ans&=\sum_{t=1}^n\sum_{d=1}^{n\over t}(1-|\mu(d)|)\\ &=\sum_{t=1}^nF({n\over t}) \end{aligned}
ans=t=1∑nd=1∑tn(1−∣μ(d)∣)=t=1∑nF(tn)
这里这么做是为了使得后面的式子只与
n
t
{n\over t}
tn有关。
现在分析
F
(
n
)
F(n)
F(n):它的意义其实就是求1~n内含有平方因子的数的个数。
这里采用的方法是利用莫比乌斯函数进行容斥:
F
(
n
)
=
n
−
∑
i
=
1
n
μ
(
i
)
n
i
2
F(n)=n-\sum_{i=1}^{\sqrt{n}}\mu(i){n\over i^2}
F(n)=n−i=1∑nμ(i)i2n
为什么?我们想下,我们若直接
n
i
2
{n\over i^2}
i2n求出来的是
i
2
i^2
i2的倍数,但如果直接算
∑
i
=
1
n
\sum_{i=1}^n
∑i=1n,之间会有重复的,比如,同时是
2
2
2^2
22和
3
2
3^2
32的倍数,那么,我们就需要-
(
2
∗
3
)
2
(2*3)^2
(2∗3)2,而前面的正负号不正好和莫比乌斯函数的定义相吻合吗?据此可以进行容斥。
补:为什么枚举到
n
\sqrt{n}
n?1~n中的数,若含有平方因子,则这个平方因子的算术平方根最大为
n
\sqrt n
n,不可能更大。
AC代码
#include <bits/stdc++.h>
using namespace std;
template<typename T>
void read(T&x){
x=0;
int f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f*=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+(ch-'0');
ch=getchar();
}
}
//====================================================
typedef long long ll;
int a,b;
const int maxn=3e6+10;
bool vis[maxn];
int pri[maxn],tot;
int mu[maxn];
void init(){
mu[1]=1;
for(int i=2;i<maxn;++i){
if(!vis[i])pri[++tot]=i,mu[i]=-1;
for(int j=1;j<=tot&&i*pri[j]<maxn;++j){
vis[i*pri[j]]=1;
if(i%pri[j]==0)break;
mu[i*pri[j]]=-mu[i];
}
}
//cerr<<"**"<<mu[8]<<" "<<mu[7]<<endl;
}
/*ll cal(int x){
ll res=0;
for(int i=1;i<=x;++i){
int add=0;
for(int d=1;d<=sqrt(i);++d){
if(i%d==0){
add+=(1-abs(MUL(d)));
if(d*d!=i){
add+=(1-abs(MUL(i/d)));
}
}
}
res+=add;
}
return res;
}*/
int cal(int n){
if(n==0) return 0;
ll res=n;
int lim=sqrt(n);
for(int i=1;i<=lim;++i){
res-=mu[i]*(n/i/i);
}
return res;
}
ll solve(int n){
ll res=0;
for(int l=1,r;l<=n;l=r+1){
int now=n/l;
r=n/now;
res+=1ll*(r-l+1)*cal(now);
}
return res;
}
int main(){
//freopen("in.txt","r",stdin);
init();
read(a),read(b);
cout<<solve(b)-solve(a-1)<<endl;
return 0;
}