题目
求(sum_{i=l}^rmu(i),r-lleq 10^5,1leq lleq rleq 10^{18})
分析
其实有一道可以算是弱化版的题目
这种类型的tricks就是枚举质数然后将([l,r])中该质数的倍数算莫比乌斯函数(比如说)
但这道题恰恰恶心在无法将所有在根号内的质数都算出来,
考虑如果([l,r])中存在一个数按照刚才的方法还剩下一个完全平方数,那么莫比乌斯函数为0,
如果按照刚才的方法还剩下一个质数,那就得用Miller-Rabin判断,符号取反;
如果是一个合数,那么它显然是由两个质数相乘得到的,符号不变。
时间复杂度(O((r-l)log(r-l)))(不愧是小清新数学题)
代码
#include <cstdio>
#include <cmath>
#define rr register
using namespace std;
typedef long long lll;
const int P[5]={2,3,7,61,24251},N=1000011;
int prime[N],v[N],mu[N],cnt,ans; lll f[N],l,r;
inline lll mul(lll a,lll b,lll mod){return (a*b-(lll)((long double)a/mod*b)*mod+mod)%mod;}
inline lll ksm(lll x,lll y,lll mod){
rr lll ans=1;
for (;y;y>>=1,x=mul(x,x,mod))
if (y&1) ans=mul(ans,x,mod);
return ans;
}
inline bool mr(lll n){
if(n==46856248255981ll||n<2) return 0;
if(n==2||n==3||n==7||n==61||n==24251) return 1;
if (!(n&1)||!(n%3)||!(n%7)||!(n%61)||!(n%24251)) return 0;
rr lll m=n-1; rr int Cnt=0;
while (!(m&1)) m>>=1,++Cnt;
for (rr int i=0;i<5&&P[i]<n;++i){
rr lll now=ksm(P[i],m,n),last=now;
for (rr int j=1;j<=Cnt;++j){
now=mul(now,now,n);
if (now==1&&last!=1&&last!=n-1) return 0;
last=now;
}
if (now!=1) return 0;
}
return 1;
}
signed main(){
scanf("%lld%lld",&l,&r);
for (rr int i=2;i<N;++i){
if (!v[i]) prime[++cnt]=i;
for (rr int j=1;j<=cnt&&prime[j]*i<N;++j){
v[i*prime[j]]=1;
if (i%prime[j]==0) break;
}
}
for (rr lll i=l;i<=r;++i) mu[i-l]=1,f[i-l]=i;
for (rr int i=1;i<=cnt;++i){
rr int I=prime[i];
for (rr lll j=((l-1)/I+1)*I;j<=r;j+=I){
rr int CNT=0;
while (f[j-l]%I==0) ++CNT,f[j-l]/=I;
if (CNT>1) mu[j-l]=0; else mu[j-l]*=-1;//指数大于1莫比乌斯函数为0,否则取反
}
}
for (rr lll i=l;i<=r;++i)
if (f[i-l]>1){
if (floor(sqrt(f[i-l]))==sqrt(f[i-l])) mu[i-l]=0;//完全平方数为0
else if (mr(f[i-l])) mu[i-l]*=-1;//质数符号取反
ans+=mu[i-l];
}else ans+=mu[i-l];
return !printf("%d",ans);
}