• #莫比乌斯函数,Miller-Rabin#洛谷 3653 小清新数学题


    题目

    (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);
    }
    
  • 相关阅读:
    4-18
    Vue学习 2017-4-9
    前端杂谈
    不错的博客哦!
    待整理知识杂项
    Vue学习历程
    王工的权限理解
    【NX二次开发】图标图像
    【转】C++怎么读写windows剪贴板的内容?比如说自动把一个字符串复制.
    获取计算机名
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/13821724.html
Copyright © 2020-2023  润新知