题目链接:
题目大意:
给出一个序列,序列中的每一个数都不是数列中其他数的幂,问序列中的第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 () );
}
}