[CSP-S模拟测试]:123567(莫比乌斯函数+杜教筛+数论分块)

题目传送门(内部题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++

原文地址:https://www.cnblogs.com/wzc521/p/11748931.html