题意:
给你一个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; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-11-09 18:22:24