【洛谷3653】小清新数学题(数论)

点此看题面

  • (sum_{i=L}^Rmu(i))
  • (1le lle rle10^{18},r-lle10^5)

一道有趣的数论题

考虑(l,r)范围很大,我们最多只能筛出(10^6),也就是(O(sqrt[3]r))范围内的素数。

对于一个需要求解的(mu(x)),我们可以先把它当中(le10^6)的质因子先全部除去,同时维护出这部分的(mu)值。

而剩下的部分如果不为(1),则最多由两个(>10^6)的质因子相乘而得。

如果剩下的是一个质数(可以用(MillerRabin)检测),那么答案就是在原(mu)值的基础上再乘个(-1)

如果剩下的是一个平方数,那么答案就是(0)

否则,剩下的是两个不同的大质数,那么答案就是在原(mu)值的基础上乘两次(-1),也就是原答案。

前面除质因子的过程最好不要枚举数去找质因子,而是枚举质因子直接扫过区间中的数,这样就能避免无效枚举。

代码:(O((r-l)log^2r))

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define S 1000000
#define LL long long
using namespace std;
int Mu[N+5];LL v[N+5];
int Pt,P[S+5];I void Sieve() {for(RI i=2,j;i<=S;++i)
	for(!P[i]&&(P[++Pt]=i),j=1;j<=Pt&&i*P[j]<=S;++j) if(P[i*P[j]]=1,!(i%P[j])) break;}
namespace MR//MillerRabin素数测试
{
	const int pt=4,p[pt]={2,3,13,19};
	I LL QM(Con LL& x,Con LL& y,Con LL& X) {return (x*y-(LL)(1.0L*x*y/X)*X+X)%X;}//快速乘
	I LL QP(LL x,LL y,Con LL& X) {LL t=1;W(y) y&1&&(t=QM(t,x,X)),x=QM(x,x,X),y>>=1;return t;}//快速幂
	I bool T(Con LL& x,CI p) {if(!(x%p)||QP(p,x-1,x)^1) return 0;//如果是倍数或不符合费马测试
		LL k=x-1,t;W(!(k&1)) if((t=QP(p,k>>=1,x))^1) return t==x-1;return 1;}//二次探测直至不为1
	I bool IsP(Con LL& x) {for(RI i=0;i^pt;++i) {if(x==p[i]) return 1;if(!T(x,p[i])) return 0;}return 1;}//枚举质数检测
}
int main()
{
	LL i,j,l,r;RI t=0;for(Sieve(),scanf("%lld%lld",&l,&r),i=l;i<=r;++i) v[i-l+1]=i,Mu[i-l+1]=1;//初始化每个数值为自身,μ为1
	for(j=1;j<=Pt;++j) for(i=((l-1)/P[j]+1)*P[j]-l+1;i<=r-l+1;i+=P[j]) Mu[i]*=-1,!((v[i]/=P[j])%P[j])&&(Mu[i]=0);//枚举质因子去区间内更新
	#define IsSqr(x) ((LL)sqrt(x)*(LL)sqrt(x)==(x))//判断平方数
	for(i=1;i<=r-l+1;t+=Mu[i++]) Mu[i]&&v[i]^1&&(MR::IsP(v[i])?Mu[i]*=-1:IsSqr(v[i])&&(Mu[i]=0));//对剩余数判断是质数/平方数/两个大质数相乘
	return printf("%d
",t),0;
}
败得义无反顾,弱得一无是处
原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu3653.html