[51NOD1244]莫比烏斯函式之和
阿新 • • 發佈:2019-01-03
題目大意
給定
題目分析
杜教篩裸題。
令
只需要計算形如
積分算得時間複雜度:
更多積性函式字首和相關請參考2016年任之洲的國家集訓隊論文《積性函式求和的幾種方法》以及唐老師的部落格。
程式碼實現
第一道杜教篩,寫得及其醜。
關於那個 )
#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;
}