bzoj 2440 (莫比乌斯函数)

bzoj 2440 完全平方数

题意:找出第k个不是完全平方数的正整数倍的数。

例如 4  9  16  25 36什么的
通过容斥原理,我们减去所有完全数  4有n/4个,但是先36这种会被重复减去,
所有我们还需要加上类似36的数,然后你会发现这些数前面的符号和他们开根号的
莫比乌斯函数一样
数据很大有1e9,如果先进行预处理再从头到尾找感觉不现实,考虑使用二分,枚举mid,
然后每次查找1到mid中不是完全平方数的正整数倍的数的个数


Orz:机制的二分使用


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
typedef long long ll;
using namespace std;

const int inf = 0x3f3f3f3f;
const int maxn = 1e5;
int tot;
int is_prime[maxn];
int mu[maxn];
int prime[maxn];

void Moblus()
{
    tot = 0;
    mu[1] = 1;
    for(int i = 2; i < maxn; i++)
    {
        if(!is_prime[i])
        {
            prime[tot++] = i;
            mu[i] = -1;
        }

        for(int j = 0; j < tot && i*prime[j] < maxn; j++)
        {
            is_prime[i*prime[j]] = 1;
            if(i % prime[j])
            {
                mu[i*prime[j]] = -mu[i];
            }
            else
            {
                mu[i*prime[j]] = 0;
                break;
            }
        }
    }
    
}

ll get_(ll mid)
{
    ll num = 0;
    for(int i = 1; i*i <= mid; i++)
    {
        num += (ll)mu[i]*(mid/(i*i));
    }
    return num;
}

int main()
{
    int T;
    Moblus();
    scanf("%d",&T);
    while(T--)
    {
        ll k;
        scanf("%lld",&k);
        ll l = 1;
        ll r = 2*k+1;
        while(l <= r)
        {
            ll mid = (l+r)>>1;
            ll num = get_(mid);
            if(num < k)
                l = mid + 1;
            else
                r = mid - 1;
        }
        printf("%lld\n",l);
    }
}




你可能感兴趣的:(数论)