题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5297
题意:给出n和r,求数列Y的第n个元素是多少。其中数列Y是正整数数列去除a^b(2<=b<=r)后的数。
解法:
假设我们知道了cal(x)表示包括x在内的x之前这个序列有多少个数。
那么显然我们就可以直接二分乱搞就好了。
然后cal怎么做呢?
x^(1/b)就表示x范围内有多少个a^b次方的数,然后根据这个容斥一波就好了。
比如你减去了2次方的,减去了3次方的,但是你多减了6次方的,你得加回去。
然后这个题坑的是二分会TLE,要用迭代才可以过,具体的过程如下: 给出一个数n,则1~n以内的正整数必定会有被去除的(假设被去除x1个),则这n个数中只有(n-x1)个数在Y数列中;如果想得到n个数在Y数列中,那么我们至少要在这n个数后面加上x1个数,设n1=n+x1,则在1~n1内的数有多少在Y数列中呢(假设有m个在Y数列中,去除了x2个)?如前面所说,在1~n1内的数最多有n个数在Y数列中(即m<=n),此时判断m与n是否相等。如果相等,则Y数列中第n个数为(n+x1);如果不相等,则继续在(n+x1)数后面再加x2个数,继续判断……一直加到某个数M,使得1~M内的数在Y数列中刚好有n个。

//HDU 5297

#include <bits/stdc++.h>
using namespace std;
int prime[19] = {-2, -3, -5, -7, -11, -13, -17, -19, -23, -29, -31, -37, -41, -43, -47, -53, -59, -61, -67};
vector <int> ie;

void init(int r)
{
    ie.clear();
    for(int i = 0; abs(prime[i]) <= r; i++){
        int tt = ie.size();
        for(int j = 0; j < tt; j++){
            if(abs(prime[i]*ie[j]) <= 63){
                ie.push_back(prime[i]*ie[j]);
            }
        }
        ie.push_back(prime[i]);
    }
}

long long f(long long x) ///计算1-x的范围内有多少数存在于Y数列中
{
    if(x == 1) return 0;
    long long ans = x;
    for(int i  = 0; i < ie.size(); i++){
        ///若a^b=pow(a,b)=x则b=pow(x,1.0/a) ;
        ///+0.5为了保证精度;-1是暂时不包含1(因为当a=1时,a^b一定会等于1)
        long long tmp = (long long)(pow(x+0.5, 1.0/abs(ie[i]))) - 1;
        if(ie[i] < 0) ans -= tmp;
        else ans += tmp;
    }
    return ans-1;///减去刚才没有包含在内的1
}

///迭代法求Y序列第n个数
long long work(long long n, int r)
{
    init(r);
    long long ans = n;
    while(1){
        long long tmp = f(ans); ///保留下来的数的个数
        if(tmp == n) break;
        ans += n-tmp;///每次加上被删除的数的个数
    }
    return ans;
}


int main()
{
    int T, r;
    long long n;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%lld%d", &n, &r);
        printf("%lld\n", work(n, r));
    }
    return 0;
}