BZOJ-2440: [中山市选2011]完全平方数

[文章目录]

Description

小 X 自幼就很喜欢数。但奇怪的是,他十分讨厌完全平方数。他觉得这些数看起来很令人难受。由此,他也讨厌所有是完全平方数的正整数倍的数。然而这丝毫不影响他对其他数的热爱。 这天是小X的生日,小 W 想送一个数给他作为生日礼物。当然他不能送一个小X讨厌的数。他列出了所有小X不讨厌的数,然后选取了第 K个数送给了小X。小X很开心地收下了。然而现在小 W 却记不起送给小X的是哪个数了。你能帮他一下吗?

k<=10^9。显然我们不能线性筛。那么我们考虑二分,对于一个mid,我们找1~mid中有都少个数满足条件,考虑容斥原理。1~n中2x2的倍数有n/(2x2)个。然后3同理。当遇到一个数n的时候,对答案累加的值就是n/()*μ(i)。据说μ(i)也被称作约数的容斥系数。那么,我们快筛mu到10^7,然后每次O(1)查询。时间复杂度:O(Tlogx√x)级别。据测量,x<=17亿。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 10000000
using namespace std;
typedef long long ll;
int mu[10001000],pri[701000],cnt;
bool v[10001000];
void quick_mu()
{
    mu[1]=1;
    for(int i=2;i<=N;i++)
    {
        if(!v[i]) pri[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&i*pri[j]<=N;j++)
        {
            v[i*pri[j]]=1;
            if(i%pri[j]==0)
            {
                mu[i*pri[j]]=0;
                break;
            }
            else mu[i*pri[j]]=mu[i]*-1;
        }
    }
}
ll get_num(const ll x)
{
    ll re=x;
    for(ll i=2;i*i<=x;i++)
        re+=(x/(i*i))*mu[i];
    return re;
}
int main()
{
    quick_mu();
    ll T,k;
    scanf("%lld",&T);
    while(T--)
    {
        scanf("%lld",&k);
        ll l=1,r=1700000000ll,mid;
        while(l<r)
        {
            mid=(r&l&1)+(l>>1)+(r>>1);
            if(get_num(mid)>=k) r=mid;
            else l=mid+1;
        }
        printf("%lld\n",r);
    }
    return 0;
}

 

发表评论

邮箱地址不会被公开。 必填项已用*标注