题目链接: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;
}