题目大意
给定
a
和
∑i=abμ(i)
2≤a≤b≤1010
题目分析
杜教筛裸题。
令
S(n)=∑ni=1μ(i)
。用恒等函数
1
卷上
μ
函数得到单位函数
ϵ
,于是有:
S(n)=1−∑i=2nS(⌊ni⌋)
只需要计算形如 ⌊nx⌋ 的数的 S 值。对小于等于
积分算得时间复杂度:
O⎛⎝⎜∫n13x=1nx−−√dx⎞⎠⎟=O(n23)
更多积性函数前缀和相关请参考2016年任之洲的国家集训队论文《积性函数求和的几种方法》以及 唐老师的博客。
代码实现
第一道杜教筛,写得及其丑。
关于那个
S(⌊nx⌋)
怎么存,对于
⌊nx⌋
开一个表直接存,对于
⌊nx⌋>n√
另外开一个表存在
x
<script type="math/tex" id="MathJax-Element-17">x</script>这个位置。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long LL;
const int L=4641600;
const int N=100050;
const int M=N<<1;
int mu[L],sum[L],pri[L],f[L];
bool mark[L];
LL S[2][N];
LL num[M];
int l,s,cnt;
LL a,b;
int id(LL x,LL n){return x>s?n/x:x;}
void pre(LL n)
{
memset(mark,0,sizeof mark),memset(pri,0,sizeof pri);
l=pow(n,2.0/3.0),s=sqrt(n);
mark[1]=1,f[1]=1,mu[1]=1;
for (int i=2;i<=l;++i)
{
if (!mark[i]) mark[i]=1,f[pri[++pri[0]]=i]=i,mu[i]=-1;
for (int j=1,k;j<=pri[0];++j)
{
if (1ll*pri[j]*i>l) break;
mark[k=pri[j]*i]=1,f[k]=pri[j];
mu[k]=f[k]==f[i]?0:-mu[i];
if (!(i%pri[j])) break;
}
}
for (int i=1;i<=l;++i) sum[i]=sum[i-1]+mu[i];
cnt=0;
for (LL st=1,en,x;st<=n;st=en) num[++cnt]=x=n/st,en=n/x+1;
}
LL sieve(LL n)
{
pre(n);
for (int sign,idn,i=cnt;i>=1;--i)
{
idn=id(num[i],n),sign=idn==num[i];
if (num[i]<=l)
{
S[sign][idn]=sum[num[i]];
continue;
}
LL res=1;
for (LL st=2,en,x;st<=num[i];st=en)
{
x=num[i]/st,en=num[i]/x+1;
int idn_=id(x,n),sign_=idn_==x;
res-=(en-st)*S[sign_][idn_];
}
S[sign][idn]=res;
}
return S[0][1];
}
int main()
{
freopen("mobius.in","r",stdin),freopen("mobius.out","w",stdout);
scanf("%lld%lld",&a,&b);
printf("%lld\n",sieve(b)-sieve(a-1));
fclose(stdin),fclose(stdout);
return 0;
}