题目传送门:【BZOJ 2440】
题目大意:多组数据,求第 k 个不含平方数因子的数。(T ≤ 50,1 ≤ k ≤ 10 9 )
题目分析:
一看题目中求出不含平方数因子的数,马上就能想到,它很有可能和 μ(x) != 0 有关。(这里的 x 为任意一整数)
由题,由于 k 最大为 10 9 ,线性算法(例如暴力扫一遍求出第 k 个这样的数)时间复杂度无法承受,于是考虑二分。这时,我们需要对题目进行转化。
设第 k 个不含平方数因子的数为 p,根据题意,易得 p ≥ k。又因为在前 2k 个数中,含有平方数因子的数的个数不超过
⌊2k22⌋
+
⌊2k32⌋
+
⌊2k42⌋
+……+
⌊2kn2⌋
≥
k
( 其中
证明:
⌊2k22⌋+⌊2k32⌋+……+⌊2kn2⌋=2k∗⌊122⌋+⌊132⌋+……+⌊1n2⌋
≤2k∗(11∗3+12∗4+13∗5+……+1(n−1)∗(n+1))
裂项相消后得
≤2k∗12∗(1−13+12−14+13−15+……+1n−2−1n+1n−1−1n+1)
≤k∗(32+1(n−1)∗(n+1))
由于 1(n−1)∗(n+1) 在 n ≥ 2时单调递减且恒大于 0,所以原式 > 3k2 ,即原式 > k
所以:
所以,我们可以对 p 在 [k,2k] 内进行二分操作,然后看它是否等于 k。
根据容斥原理,满足要求的 ans = p -(只有一个质数因子次数 ≥ 2的个数)+(只有2个质数因子 ≥ 2的个数)- ……,经转化后即为 ∑p√i=1μ(i)∗pi2 。此时即为最终的答案表达式。
下面附上代码:
- #include<cstdio>
- const int MX=45005;
- int prime[MX],miu[MX],ptot,k;
- bool isnot[MX];
- void get_miu(int n){ //线性筛求miu值
- isnot[1]=true;
- miu[1]=1;
- for (int i=2;i<=n;i++){
- if (!isnot[i]){
- prime[++ptot]=i;
- miu[i]=-1;
- }
- for (int t=1;t<=ptot;t++){
- int j=prime[t]*i;
- if (j>n) break;
- isnot[j]=true;
- miu[j]=miu[prime[t]]*miu[i];
- if (i%prime[t]==0){
- miu[j]=0;
- break;
- }
- }
- }
- }
- bool check(int m){
- long long tot=0;
- for (int i=1;i*i<=m;i++){
- tot+=miu[i]*(m/(i*i)); //根据容斥原理计算
- }
- return tot>=(long long)k;
- }
- int main(){
- get_miu(45000);
- int T;
- scanf(”%d”,&T);
- while (T–){
- scanf(”%d”,&k);
- long long lf=k,rt=2*k,mid;
- while (lf<rt){
- mid=(lf+rt)>>1;
- if (check(mid)) rt=mid;
- else lf=mid+1;
- }
- printf(”%lld\n”,lf);
- }
- return 0;
- }