bzoj2440 完全平方数 莫比乌斯值+容斥+二分

莫比乌斯值+容斥+二分
/**
题目:bzoj2440 完全平方数
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2440
题意:求第k个小x数。小x数是指不存在某个素因子次数>=2。1也是小x数。

思路:二分x,求[1,x]有多少个小x数。如果一个数是某个素数的平方的倍数,那么不是小x数。

所以要减去。2^2的倍数, 3^2的倍数, 5^2的倍数. 由于减去2的平方的倍数和3的平方的倍数把6的平方的倍数多减去了一次。所以要加回去。

ans = sigma[1,sqrt(x)] mu[i]*x/i/i ;


*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <iostream>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
#define ms(x,y) memset(x,y,sizeof x)
typedef pair<int, int> P;
const LL INF = 1e10;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 100;
int prime[maxn], tot, not_prime[maxn];
int mu[maxn];
map<LL,LL> mp;
void get()
{
    mu[1] = 1;
    tot = 0;
    for(int i = 2; i < maxn; i++){
        if(!not_prime[i]){
            prime[++tot] = i;
            mu[i] = -1;
        }
        for(int j = 1; prime[j]*i<maxn; j++){
            not_prime[prime[j]*i] = 1;
            if(i%prime[j]==0){
                mu[prime[j]*i] = 0;
                break;
            }
            mu[prime[j]*i] = -mu[i];
        }
    }
}

LL solve(LL x)
{
    LL ans = 0;
    for(LL i = 1; i*i<=x; i++){
        ans += mu[i]*x/i/i;
    }
    return ans;
}
int main()
{
    //freopen("in.txt","r",stdin);
    int T;
    int k;
    get();
    mp.clear();
    cin>>T;
    while(T--)
    {
        scanf("%d",&k);
        LL lo = 1, hi = INF, mid;
        LL ans = INF;
        while(lo<=hi){
            mid = (lo+hi)/2;
            if(mp[mid]!=0){///加了map后省了一半的时间,注意使用场景。有时候可能不能用。有时候时间增大。
                if(mp[mid]>=k){
                    ans = mid;
                    hi = mid-1;
                }else
                {
                    lo = mid+1;
                }
                continue;
            }
            if((mp[mid]=solve(mid))>=k){
                ans = mid;
                hi = mid-1;
            }else lo = mid+1;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted on 2017-08-14 20:58  hnust_accqx  阅读(140)  评论(0编辑  收藏  举报

导航