技巧1:对这种求和交换顺序
技巧2:对这种求和交换顺序,看下面过程
A.牛客网练习赛25A,枚举约数个数和
//注意这里将d的范围提高到n,对结果无影响
//令i=id,交换求和顺序,从枚举i变成枚举d
B.51nod1742,莫比乌斯反演
//有平方因子贡献为1
//1-有平方因子就是无平方因子的贡献
分别求和,前面跟A一模一样,后面
//同样提高d求和的上限到n,然后变成这样
//令t=td,交换求和就会得到下面,然后提高i求和上限到n,
//令d=i^2*d,交换求和顺序得到下面,因为i*i<=n,所以i枚举到sqrt(n)即可
Get1()就是上面A.求的那个
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int pri[45005];bool isp[45005];int mu[45005];ll F[10000005];
map<int,ll>mp;
void init(int n,int pp)//预处理sqrtn个mu
{
int p=0;mu[1]=1;
for(int i=2;i<=n;i++)
{
if(isp[i]==0) pri[++p]=i,mu[i]=-1;
for(int j=1;j<=p&&i*pri[j]<=n;j++)
{
isp[i*pri[j]]=1;
if(i%pri[j]==0)
{
mu[i*pri[j]]=0;break;
}
else mu[i*pri[j]]=-mu[i];
}
}
}
ll get1(ll n)//加个记忆化 46ms T很小,map可不加
{
if(n<=10000000&&F[n])return F[n];
if(mp[n])return mp[n];
ll ans=0;int nxt=0;
for(int i=1;i<=n;i=nxt+1)
{
nxt=n/(n/i);
ans+=1ll*(n/i)*(ll)(nxt-i+1);
}
if(n<=10000000) return F[n]=ans;
return mp[n]=ans;
}
int main()
{
ll n,n1;scanf("%lld %lld",&n,&n1);n--;
init((int)sqrt(n1+0.5),1e9+7);
ll ans=get1(n);
for(int i=1;i<=n/i;i++)
ans-=1ll*mu[i]*get1(n/i/i);
ll ans1=get1(n1);
for(int i=1;i<=n1/i;i++)
ans1-=1ll*mu[i]*get1(n1/i/i);
printf("%lld\n",ans1-ans);
}