题目传送门(内部题92)
输入格式
一个整数$n$。
输出格式
一个答案$ans$。
样例
样例输入:
13
样例输出:
9
数据范围与提示
对于$20\%$的数据,$nleqslant 10^6$。
对于$40\%$的数据,$nleqslant 10^{12}$。
对于$100\%$的数据,$0leqslant nleqslant 10^{18}$。
题解
这道题里的小$mu$其实就提示我们了$mu$,也就是莫比乌斯函数。
那么,我们可以列出式子:
$$ans=sum limits_{i=1}^sqrt{n}mu(i)leftlfloorfrac{n}{i^2} ight floor$$
但是这个式子还是不足矣$AC$,考虑优化。
先考虑对于一段内的$leftlfloorfrac{n}{i^2}
ight
floor$是相等的,想到数论分块,对于一个区间$[l,r]$,满足$leftlfloorfrac{n}{l^2}
ight
floor=leftlfloorfrac{n}{r^2}
ight
floor$,那么现在就需要想办法快速求出每一段的$sum limits_{i=l}^rmu(i)$。
很快想到杜教筛,然后这道题就没了……
时间复杂度:$Theta(n^{frac{2}{5}})$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
using namespace std;
map<int,int>mp;
long long n;
long long ans;
bool vis[30000001];
int prime[30000001],mu[30000001],cnt;
void pre_work()
{
mu[1]=1;
for(int i=2;i<=30000000;i++)
{
if(!vis[i])
{
prime[cnt++]=i;
mu[i]=-1;
}
for(int j=0;j<cnt&&i*prime[j]<=30000000;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j])mu[i*prime[j]]=-mu[i];
else{mu[i*prime[j]]=0;break;}
}
}
}
int get(int x)
{
if(x<=30000000)return mu[x];
if(mp[x])return mp[x];
int res=1;
for(int i=2,j;i<=x;i=j+1)
{
j=x/(x/i);
res-=get(x/i)*(j-i+1);
}
return mp[x]=res;
}
int main()
{
pre_work();scanf("%lld",&n);
for(int i=1;i<=30000000;i++)mu[i]+=mu[i-1];
for(long long i=1,j;i*i<=n;i=j+1)
{
j=sqrt(n/(n/(i*i)));
ans+=(n/(i*i))*(get(j)-get(i-1));
}
printf("%lld",ans);
return 0;
}
rp++