题目链接:

点击打开链接

题目大意:

给出一个序列,序列中的每一个数都不是数列中其他数的幂,问序列中的第n个数的值

题目分析”:

首先要找出如果能够知道num之前的数有多少个存在于数列Y中,那么我们很容易就可以利用二分得到答案,那么我们定义f(n)=前n个自然数当中在Y序列中的数的个数。

那么f(n)应该怎么做呢,sqrt(n)就是在二次方情况下需要抹去的数的个数,依次类推,我们能够得到r次方以内的分别得到需要抹去的数的个数,但是需要注意的是这些数当中会有重复的,而且每个质数,会把只包含它的合数全部重复,所以我们只统计质数幂的情况,然后利用容斥定理排除质数中的重复的情况,得到f(n)

然后进行二分即可。。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cmath>

using namespace std;

int p[]={-2,-3,-5,-7,-11,-13,-17,-19,-23,-29,-31,-37,-41,-43,-47,-53,-59,-61,-67};

typedef long long LL;

int r,t;
LL n;
vector<int> cal;

void init ( )
{
    cal.clear();
    for ( int i = 0 ; abs(p[i]) <= r ;i++ )
    {
        int len = cal.size();
        for ( int j = 0 ; j < len ; j++ )
        {
            if ( abs(cal[j]*p[i]) < 64 )
                cal.push_back ( p[i]*cal[j] );
        }
         cal.push_back( p[i] );
    }
}

LL get ( LL x )
{
    if ( x == 1 ) return 0;
    LL ans = x;
    for ( int i = 0 ; i < cal.size () ; i++ )
    {
        LL temp = (LL)( pow ( x+0.5 , 1.0/(abs(cal[i])) )-1);
        if ( cal[i] < 0 )
            ans -= temp;
        else
            ans += temp;
    }
    return ans - 1;
}

/*LL ans ( )
{
    init ( );
    LL a = n;
    while (1)
    {
        LL temp = get ( a );
        //cout << a << " " << temp << endl;
        if ( temp == n ) break;
        a += n - temp;
    }
    return a;
}*/

LL ans ( )
{
    init ();
    LL l = 1 , r = 1e18 , mid;
    while ( l != r )
    {
        mid = l + r >>1;
        if ( get(mid) >= n ) r = mid;
        else  l = mid+1;
    }
    return l;
}


int main ( )
{
    scanf ( "%d" , &t );
    while ( t-- )
    {
        scanf ( "%I64d%d" , &n , &r );
        printf ( "%I64d\n" , ans () );
    }
}