完全平方数(莫比乌斯反演+二分答案)

询问第k个不是完全平方数或完全平方数整数倍的整数。
1不视作完全平方数。

输入格式 

第一行一个数t表示t组数据。
接下来t行每行一个整数表示k

输出格式 

t行,每行一个整数表示答案。

输入样例 

4
1
13
100
1234567

输出样例 

1
19
163
2030745
数据规模:
对于20%的数据1<=k<=1000
对于50%的数据1<=k<=1000000
对于100%的数据1<=k<=1000000000

题意简洁又明了,但还是有些难度的。

首先,我们不可能根据k直接算出答案是多少,那对于一个确定的数x,是否能算出它是第几个非完全平方数呢?或者能否算出在它之前有多少个完全平方数呢?答案是肯定的。

在[1,x]中,4会出现x/4次,9会出现x/9次,以此类推,但是这样找会有重复,4和9每36就会重复一次,对于n²来说,会与n的约数m——m²重复,那么我们就可以用莫比乌斯函数(容斥原理)来筛掉重复的,就可以了。这样我们可以在sqrt(x)的时间内判断了。

又因为答案是有单调性的,所以我们可以对答案进行二分,加上前面的判断,时间复杂度为O(logn *sqrt(n))。

#include<fstream>
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
using namespace std;

int T,k;
int vis[100010],mu[100010],tot,pri[100010];

void Make_mu()
{
    for (int i=2; i<=44800; i++)
    {
        if (vis[i]==0) 
        {
            tot++;
            pri[tot] = i;
            mu[i] = -1;
        }
        for (int j=1; j<=tot; j++)
        {
            int x = i*pri[j];
            if (x>100000) break;
            vis[x] = 1;
            if (i%pri[j]==0)
            {
                mu[x] = 0;
                break;
            }
            else mu[x] = -mu[i];
        }
    }
}

int sum(int x)
{
    int ret = x,cnt = 0;
    for (int i=2; i<=sqrt(x); i++)
    cnt = cnt-mu[i]*x/(i*i);
    return ret-cnt;
}

void Binary(int a,int b,int k)
{
    long long l,r,mid;
    l = a;  r = b;  
    while (l+1<r)
    {
        mid = (long long)(l+r)/2;
        if (sum(mid)<k) l = mid;
        else r = mid;
    }
    printf("%d\n",r);
}

int main()
{
    freopen("2236.in","r",stdin);
    freopen("2236.out","w",stdout);
    scanf("%d",&T);
    Make_mu();
    while (T>0)
    {
        T--;
        scanf("%d",&k);
        Binary(0,1e9+2+1e9,k);
    }
    return 0;
}

 

posted @ 2017-10-09 20:55  最终惊吓者——Janous  阅读(261)  评论(0编辑  收藏  举报