莫比乌斯函数,由德国数学家和天文学家莫比乌斯提出。梅滕斯(Mertens)首先使用μ(n)(miu(n))作为莫比乌斯函数的记号。具体定义如下:
如果一个数包含平方因子,那么miu(n) = 0。例如:miu(4), miu(12), miu(18) = 0。
如果一个数不包含平方因子,并且有k个不同的质因子,那么miu(n) = (-1)^k。例如:miu(2), miu(3), miu(30) = -1,miu(1), miu(6), miu(10) = 1。
给出一个区间[a,b],S(a,b) = miu(a) + miu(a + 1) + …… miu(b)。
例如:S(3, 10) = miu(3) + miu(4) + miu(5) + miu(6) + miu(7) + miu(8) + miu(9) + miu(10)
= -1 + 0 + -1 + 1 + -1 + 0 + 0 + 1 = -1。
设 f(n)=∑ni=1μ(i)
所以 ans=f(b)−f(a−1)
一开始不知道怎么办。。。但是突然想到了一个东西。
∑d|nμ(d)=0 但是如果n=1,这个东西就等于1。
发现了求和性质和1的这个特殊性。
∑ni=1∑d|imu(d)=1
熟练掌握内层外移的话,这种东西只可以转化的。
这个式子= ∑nd=1∑ndi=1mu(i)
再带入f数组转化一下。
这个式子= ∑nd=1f(nd)
因为 ∑nd=2f(nd)+f(n)=1
所以 f(n)=1−∑nd=2f(nd)
然后再分块一下。
打一个记忆化搜索。像模拟链表一样。
空间不要都要long long,会爆啊!
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
typedef long long ll;
const int maxn=5000007,mo=857777;
int i,j,k,l,t,n,m,miu[maxn],p[maxn],sum[maxn];
ll a,b,ans,chang[mo];
int next[mo],last[mo],first[mo],num;
bool bz[maxn];
void add(int x,int y,ll z){
last[++num]=y;next[num]=first[x];first[x]=num;chang[num]=z;
}
int suan(ll x){
int i,j=x%mo,k=1;ll l=2,r;
if(x<=maxn)return sum[x];
rep(i,j)if(last[i]==x)return chang[i];
while(l<=x){
r=x/(x/l);
k-=(r-l+1)*suan(x/l);
l=r+1;
}
add(j,x,k);
return k;
}
int main(){
scanf("%lld%lld",&a,&b);
miu[1]=1;
fo(i,2,maxn){
if(!bz[i]){
miu[i]=-1;
p[++p[0]]=i;
}
fo(j,1,p[0]){
t=i*p[j];if(t>maxn)break;bz[t]=1;
if(!(i%p[j])){break;}
miu[t]=-miu[i];
}
}
fo(i,1,maxn)sum[i]=sum[i-1]+miu[i];
printf("%d",suan(b)-suan(a-1));
}