【学术篇】bzoj2440 [中山市选2011]完全平方数

-题目の传送门-

题目大意: 找到第k个无平方因子数.

看到数据范围很大, 我们要采用比\(O(n)\)还要小的做法.
考虑如果前\(x\)个数中有\(k-1\)个无平方因子数, 而前\(x+1\)个数中有\(k\)个无平方因子数, 那么\(x\)即为所求.
而由某种我不会的方式可以证明出答案是不会超过\(2n\)的, 所以我们可以二分答案.
问题就转化成了求前\(x\)个数中有多少个无平方因子数.

我们要求无平方因子数就要把所有的有平方因字数筛掉, 为了保证不重不漏, 我们考虑容斥.
我们枚举\(1\sim \sqrt n\)中的所有无平方因子数, 将其平方及其平方的倍数删掉.
这样的话有偶数个质因子的数就被多删了一遍, 我们再将他们加回来.
我们设容斥系数是\(k(i)\), 那么

\[ans=\sum_{i=1}^{\left \lfloor \sqrt n \right \rfloor}k(i){\left \lfloor \frac n{i^2} \right \rfloor} \]

而根据上面的分析, 容斥系数\(k(i)\)满足:

\[k(i)=\left\{\begin{matrix} 0,\ 有平方因子\\ 1,\ 无平方因子, \pi(i)是偶数\\ -1,\ 无平方因子, \pi(i)是奇数 \end{matrix}\right. \]

非常巧合的是, 这个容斥系数跟\(\mu\)好像是一样的啊...
所以我们就可以得出

\[ans=\sum_{i=1}^{\left \lfloor \sqrt n \right \rfloor}\mu(i){\left \lfloor \frac n{i^2} \right \rfloor} \]

这样预处理一波\(\mu\), 然后每次\(O(\sqrt n)\)统计答案即可.
时间复杂度\(O(T*log_2n*\sqrt n)\)

代码:

#include <cstdio>
const int N=45005;
int pr[N],mu[N],tot,n;
bool np[N];
void shai(){
	mu[1]=np[1]=1;
	for(int i=2,k;i<=45000;++i){
		if(!np[i]) pr[++tot]=i,mu[i]=-1;
		for(int j=1;j<=tot&&(k=i*pr[j])<=45000;++j){
			np[k]=1;
			if(i%pr[j]==0){mu[k]=0; break;}
			mu[k]=-mu[i];
		}
	}
}
inline bool check(int x,int s=0){
	for(int i=1;i*i<=x;++i)
		s+=x/(i*i)*mu[i];
	return s>=n;
}
int main(){ shai();
	int T; scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		int l=1,r=n<<1;
		while(l<r){
			int mid=(1LL*l+r)>>1;
			if(check(mid)) r=mid;
			else l=mid+1;
		}
		printf("%d\n",r);
	}
}

这个题并和莫比乌斯反演没什么关系, 算是莫比乌斯函数的一个小应用吧...

posted @ 2018-02-06 11:23  Enzymii  阅读(206)  评论(0编辑  收藏  举报