题意:
给你一个n和一个r,求Y序列的第N项是多少。
所谓的Y序列就是,从1开始,去掉能表示成a^b(2<=b<=r)的数,所构成的序列
例如r=2
序列就是:2,3,5,6,7,8,10,11,12,13,14,15,17....
思路:
我们应该能想到需要一个函数fun(x) 求的是1~x内在Y序列里的数有多少个
这个其实不难,我们可以运用容斥原理,通过63以内的素数进行计算,并且最多做三遍,因为2*3*5*7>63
然后就是一个很神奇的方法了,这个方法特别的秒
就是迭代的方法。
假设我们现在要求第N个Y序列的数,先假设第N个数就是N,那么我们求一下fun(N)=tep
tep代表在Y序列里的有tep个数,不在的就有 N-tep个。
这样我们下次就再求 fun(N+(N-tep)) 看看是否等于N,这样不断迭代下去
直到tep==N为止
为什么这样的是对的呢
因为我们每次只加缺少的个数,其实就是假设如果加的这些数都不会被剔除的话,那么就是答案了。
所以不可能加的超过正确答案。
然后由于很明显是非常离散的,因为是次方级别的,所以迭代次数不会多。
代码:
#include"stdio.h"
#include"algorithm"
#include"string.h"
#include"iostream"
#include"queue"
#include"map"
#include"vector"
#include"string"
#include"cmath"
using namespace std;
#define ll __int64
int ss[]= {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67};
ll n;
int r;
int used[22];
ll dfs(int ii,int x,int k,int tep,double kx)
{
if(x==k)
{
return (int)(pow(kx+0.5,1.0/tep)-1); //注意+0.5控制精度!
}
if(tep>63) return 0;
ll ans=0;
for(int i=ii+1; i<18; i++)
{
if(ss[i]>r || tep*ss[i]>63) break;
if(used[i]==0)
{
used[i]=1;
ans+=dfs(i,x+1,k,tep*ss[i],kx);
used[i]=0;
}
}
return ans;
}
ll fun(ll x)
{
ll ans=0;
for(int i=1; i<5; i++)
{
memset(used,0,sizeof(used));
if(i%2) ans+=dfs(-1,0,i,1,x*1.0);
else ans-=dfs(-1,0,i,1,x*1.0);
}
return x-(ans+1);
}
int main()
{
int t;
cin>>t;
while(t--)
{
scanf("%I64d%d",&n,&r);
ll ans=n;
while(1)
{
ll tep=fun(ans);
if(tep==n) break;
ans+=n-tep;
}
printf("%I64d\n",ans);
}
return 0;
}