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