51Nod.1244.莫比乌斯函数之和(杜教筛)

时间:2023-03-09 02:10:21
51Nod.1244.莫比乌斯函数之和(杜教筛)

题目链接

51Nod.1244.莫比乌斯函数之和(杜教筛)

51Nod.1244.莫比乌斯函数之和(杜教筛)

map:

//杜教筛
#include<map>
#include<cstdio>
typedef long long LL;
const int N=5e6; int mu[N+3],P[N+3],cnt;
bool Not_P[N+3];
std::map<LL,LL> sum;
//std::map<LL,LL>::iterator it; void Init()
{
mu[1]=1;
for(int i=2;i<N;++i)
{
if(!Not_P[i]) P[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*P[j]<N;++j)
{
Not_P[i*P[j]]=1;
if(!(i%P[j])) {mu[i*P[j]]=0; break;}
mu[i*P[j]]=-mu[i];
}
}
for(int i=2;i<N;++i) mu[i]+=mu[i-1];
}
LL Calc(LL n)
{
if(n<N) return mu[n];
// if((it=sum.find(n))!=sum.end()) return it->second;//效率是几乎一样的
if(sum.count(n)) return sum[n];
LL ans=1;
for(LL nxt,i=2;i<=n;i=nxt+1)
nxt=n/(n/i),ans-=(nxt-i+1)*Calc(n/i);
return sum[n]=ans;
} int main()
{
Init();
LL a,b;scanf("%lld%lld",&a,&b);
printf("%lld",Calc(b)-Calc(a-1)); return 0;
}

数组:(使用数组这个trick存的话 对于多组询问就要重新计算了)

但是据(rqy)说map实际用到的次数并不多,所以多次询问还是直接用map吧。

//比map还要慢一点

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long LL;
const int N=5e6; int mu[N+3],P[N+3],cnt;
LL sum2[15000],Max;
bool Not_P[N+3]; void Init()
{
mu[1]=1;
for(int i=2;i<Max;++i)
{
if(!Not_P[i]) P[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*P[j]<Max;++j)
{
Not_P[i*P[j]]=1;
if(!(i%P[j])) {mu[i*P[j]]=0; break;}
mu[i*P[j]]=-mu[i];
}
}
for(int i=1;i<Max;++i) mu[i]+=mu[i-1];
}
const int EQU=-2333333;
LL Calc(LL n,LL mx)
{
if(n<Max) return mu[n];
if(sum2[mx/n]!=EQU) return sum2[mx/n];
LL ans=1;
for(LL nxt,i=2;i<=n;i=nxt+1)
nxt=n/(n/i),ans-=(nxt-i+1)*Calc(n/i,mx);
return sum2[mx/n]=ans;
} int main()
{
LL a,b;scanf("%lld%lld",&a,&b);
// printf("%.3lf %.3lf\n",pow(a,0.667),pow(b,0.667));
Max=pow(b,0.667), Init();
std::fill(sum2,sum2+15000,EQU); LL ans1=Calc(b,b);
std::fill(sum2,sum2+15000,EQU); LL ans2=Calc(a-1,a-1);
printf("%lld",ans1-ans2); return 0;
}