解题思路:
像这种求积性函数前缀和的题,可以用杜教筛来做,时间复杂度为
O(n23)
,是一种基于分治和记忆化搜索的方法。
具体可见:http://blog.csdn.net/skywalkert/article/details/50500009
注意一定要把求得的答案记忆化才能保证复杂度,本人TLE了半天不知为何。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define ll long long
using namespace std;
const int N=6000000,INF=0x3f3f3f3f;
int pn,pri[N],mu[N],sum[N],f1[N],f2[N];
ll l,r,n;
void sieve()
{
memset(mu,INF,sizeof(mu));
sum[1]=mu[1]=1;
for(int i=2;i<N;i++)
{
if(mu[i]==INF)pri[++pn]=i,mu[i]=-1;
for(int j=1;j<=pn&&1ll*i*pri[j]<N;j++)
{
int k=i*pri[j];
if(i%pri[j]==0)
{
mu[k]=0;
break;
}
mu[k]=-mu[i];
}
sum[i]=sum[i-1]+mu[i];
}
}
int &find(ll x)
{
if(x<N)return f1[x];
return f2[n/x];
}
int M(ll x)
{
if(x<N)return sum[x];
int &res=find(x);
if(res!=INF)return res;
res=1;
for(ll i=2,j;i<=x;i=j+1)
{
j=x/(x/i);
res-=(j-i+1)*M(x/i);
}
return res;
}
int solve(ll x)
{
memset(f1,INF,sizeof(f1));
memset(f2,INF,sizeof(f2));
n=x;
return M(x);
}
int main()
{
//freopen("lx.in","r",stdin);
sieve();
scanf("%lld%lld",&l,&r);l--;
cout<<solve(r)-solve(l)<<'\n';
return 0;
}