感觉和
筛挺像的???(大雾
听说貌似可以求很多东西的样子,于是就去入了个门(然而啥题都不会做。
参考博客:litble巨佬的与扩展埃氏筛(min_25筛?)玩耍
用拓展埃氏筛处理一些与素数有关的问题
求
~
之间的素数个数,
传送门
貌似线性筛会
啊(显而易见
然后就有了扩展埃氏筛这个东西。
我们考虑埃氏筛的过程:
现在最开始有一排数
,我们只知道
不是质数,而并不知道
~
哪些不是质数,于是每次发现一个质数之后就会把它的倍数全部标记成为合数,之后访问到的没有打过标记的即为质数。
换到这道题上面:
我们令
表示
~
之间的质数个数,由于最开始不知道哪些是合数,因此初始化时
之后直接往后枚举,假设现在正在处理质数
,那么对于
显然需要扣掉以
为最小质因子的合数,也就是
,(因为此时
已经被处理过并且将小于
的质数也算入内了因此要扣掉)
即:
那么我们用两个数组
来记录
的部分,其中
于是就可以处理了。
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int N=1e6+5;
typedef long long ll;
ll f1[N],f2[N],n;
int lim;
int main(){
cin>>n;
lim=sqrt(n);
for(ri i=1;i<=lim;++i)f1[i]=i-1,f2[i]=n/i-1;
for(ri p=2;p<=lim;++p){
if(f1[p]==f1[p-1])continue;
for(ri i=1;i<=lim/p;++i)f2[i]-=f2[i*p]-f1[p-1];
for(ri i=lim/p+1;(ll)i<=n/(ll)p/(ll)p&&i<=lim;++i)f2[i]-=f1[n/i/p]-f1[p-1];
for(ri i=lim;i>=(ll)p*p;--i)f1[i]-=f1[i/p]-f1[p-1];
}
cout<<f2[1];
return 0;
}
计算给定区间内所有质数之和,
传送门
解法几乎同上。
函数的递推式是
建议初学者自己手推一下。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int N=1e6+5;
typedef long long ll;
const double eps=1e-12;
double f1[N],f2[N];
ll L,R;
inline double S(const ll&x){return (double)(x+1)*(double)x/2.0;}
inline double query(ll n){
if(!n)return 0;
ll lim=sqrt(n);
for(ll i=1;i<=lim;++i)f1[i]=S(i),f2[i]=S(n/i);
for(ll p=2;p<=lim;++p){
if(fabs(f1[p]-f1[p-1])<eps)continue;
double t=f1[p-1];
for(ri i=1;i<=lim/p;++i)f2[i]-=(f2[i*p]-t)*(double)p;
for(ll i=lim/p+1;i<=lim&&i<=n/p/p;++i)f2[i]-=(double)(f1[n/i/p]-t)*(double)p;
for(ll i=lim;i>=p*p;--i)f1[i]-=(f1[i/p]-t)*(double)p;
}
return f2[1];
}
int main(){
cin>>L>>R;
printf("%.0lf",query(R)-query(L-1));
return 0;
}
用拓展埃氏筛处理一些与积性函数有关的问题
多组数据,求
满足
表示
的约数个数。
传送门
质数的处理挺简单的。
现在还需要处理合数。
考虑唯一分解定理,发现可以不断枚举当前可能的最小质因子的幂来统计答案。
可以看代码中的解析:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
typedef unsigned long long ll;
inline ll read(){
ll ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
const int N=2e6+5;
ll n,k,lim,tot,ans,f1[N],f2[N];
int pri[N];
inline void init(ll x){
lim=sqrt(x),tot=0;
if(x<=1)return;
for(ri i=1;i<=lim;++i)f1[i]=i-1,f2[i]=x/i-1;
ll t;
for(ri p=1;p<=lim;++p){
if(f1[p]==f1[p-1])continue;
pri[++tot]=p,t=f1[p-1];
for(ri i=1;i<=lim/p;++i)f2[i]-=f2[i*p]-t;
for(ri i=lim/p+1,up=min((ll)lim,n/(ll)p/(ll)p);i<=up;++i)f2[i]-=f1[x/i/p]-t;
if(lim>=(ll)p*p)for(ri i=lim,up=p*p;i>=up;--i)f1[i]-=f1[i/p]-t;
}
}
inline void solve(int pos,ll pre,ll up){
ll t=up<=lim?f1[up]:f2[n/up];
//统计一坨f(x)的贡献,其中f(x)的最大质因子为1且之前质因子的贡献为pre
ans+=(k+1)*pre*(t-f1[pri[pos-1]]);
for(ri i=pos;i<=tot;++i){
if(up<(ll)pri[i]*pri[i])return;
for(ll mult=pri[i],tim=1;mult<=up;mult*=pri[i],++tim){//枚举质数幂次统计答案
if(mult*pri[i]<up)solve(i+1,pre*(k*tim+1),up/mult);//看之后能不能更大质因子
if(tim>=2)ans+=pre*(k*tim+1);//计算f(x)的最大质因子不为1的贡献
}
}
}
int main(){
for(ri tt=read();tt;--tt){
n=read(),k=read(),ans=1;
init(n),solve(1,1,n);
cout<<ans<<'\n';
}
return 0;
}
求
的前缀和,
满足:
跟上一道题差不多,预处理时要计算出质数异或1的前缀和。
可以自己手推一下。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int mod=1e9+7,N=2e6+5,inv2=5e8+4;
typedef long long ll;
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return a>=b?a-b:a-b+mod;}
inline int mul(const int&a,const int&b){return (ll)a*b%mod;}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,a=mul(a,a))if(p&1)ret=mul(ret,a);return ret;}
inline void Add(int&a,const int&b){a=a+b>=mod?a+b-mod:a+b;}
inline void Dec(int&a,const int&b){a=a>=b?a-b:a-b+mod;}
inline void Mul(int&a,const int&b){a=(ll)a*b%mod;}
ll n,lim;
int f1[N],f2[N],s1[N],s2[N],pri[N],tot=0,ans;
inline int S(const int&x){return mul(mul(x,x+1),inv2);}
inline void init(ll x){
lim=sqrt(x),tot=0;
if(x<=1)return;
for(ri i=1;i<=lim;++i)f1[i]=i-1,f2[i]=dec(x/i%mod,1),s1[i]=dec(S(i),1),s2[i]=dec(S(x/i%mod),1);
for(ri tf,ts,p=1;p<=lim;++p){
if(f1[p]==f1[p-1])continue;
pri[++tot]=p,tf=f1[p-1],ts=s1[p-1];
for(ri i=1;i<=lim/p;++i){
Dec(f2[i],dec(f2[i*p],tf));
Dec(s2[i],mul(dec(s2[i*p],ts),p));
}
for(ri i=lim/p+1,up=min(lim,x/(ll)p/(ll)p);i<=up;++i){
Dec(f2[i],dec(f1[x/i/p],tf));
Dec(s2[i],mul(dec(s1[x/i/p],ts),p));
}
if(lim>=(ll)p*p)for(ri i=lim,up=p*p;i>=up;--i){
Dec(f1[i],dec(f1[i/p],tf));
Dec(s1[i],mul(dec(s1[i/p],ts),p));
}
}
for(ri i=1;i<=lim;++i){
Dec(s1[i],f1[i]);
if(i>=2)Add(s1[i],2);
Dec(s2[i],f2[i]);
if(n/i>=2)Add(s2[i],2);
}
}
inline void solve(int pos,int pre,ll up){
int t=up<=lim?s1[up]:s2[n/up];
Add(ans,mul(pre,dec(t,s1[pri[pos-1]])));
for(ri i=pos;i<=tot;++i){
if(up<(ll)pri[i]*pri[i])return;
for(ll mult=pri[i],tim=1;mult<=up;mult*=pri[i],++tim){
if(mult*pri[i]<up)solve(i+1,mul(pre,pri[i]^tim),up/mult);
if(tim>=2)Add(ans,mul(pre,pri[i]^tim));
}
}
}
int main(){
cin>>n,ans=1;
init(n),solve(1,1,n);
cout<<ans;
return 0;
}