HDU 5297 Y sequence

本文介绍了一种求解特定数列Y(n)的高效算法,该数列由去除特定形式幂次的所有正整数组成。通过计算排除的幂次数量,并采用容斥原理进行修正,实现了对Y数列中任意项的快速定位。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Y sequence


Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)


Problem Description
Yellowstar likes integers so much that he listed all positive integers in ascending order,but he hates those numbers which can be written as a^b (a, b are positive integers,2<=b<=r),so he removed them all.Yellowstar calls the sequence that formed by the rest integers“Y sequence”.When r=3,The first few items of it are:
2,3,5,6,7,10......
Given positive integers n and r,you should output Y(n)(the n-th number of Y sequence.It is obvious that Y(1)=2 whatever r is).
 

Input
The first line of the input contains a single number T:the number of test cases.
Then T cases follow, each contains two positive integer n and r described above.
n<=2*10^18,2<=r<=62,T<=30000.
 

Output
For each case,output Y(n).
 

Sample Input
  
2 10 2 10 3
 

Sample Output
  
13 14
 
题意:给定正整数n和r,定义Y数列为从正整数序列中删除所有能表示成a^b(2 ≤ b ≤ r)的数后的数列,求Y数列的第n个数是多少。例如n = 10, r = 3,则Y数列为2 3 5 6 7 10 11 12 13 14,第10个数是14。

思路:首先我们知道,小于n的平方数有sqrt(n)即pow(n+0.5, 1.0/2)个,立方数有pow(n+0.5, 1.0/3)个.....同理递推。(n+0.5是为了确保精度)
值得注意的是,当b是合数时例如b=6时,因为a^6 = (a^3)^2 = (a^2)^3,要求Y序列中第n个数是什么,直接求似乎有点难,我们这样想,先求n前面能表示成平方数、立方数...r方数的有多少个,假设为tmp,再让n+tmp(相当于前面筛掉了tmp个数),再依次迭代,直到新加的tmp里面没有能表示成2~r方的数即可,因为能表示成幂指数的数越往后越稀疏,所以这样复杂度就比直接二分低了,但是正如前面所说的,我们筛掉平方数时筛掉了6次方数但是晒立方数时又筛掉了6次方数,所以要用容斥来维护。

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <bits/stdc++.h>  
  2. using namespace std;  
  3. typedef long long ll;  
  4.   
  5. int p[30];  
  6. ll n, r;  
  7. vector<int> Exclu;  
  8.   
  9. void getPrime() {  
  10.         bool vis[70];  
  11.         int pos = 0;  
  12.         memset(vis, 0, sizeof(vis));  
  13.         for(int i = 2; i < 70; ++i) {  
  14.                 if(!vis[i]) {  
  15.                         p[pos++] = -i;  
  16.                 }  
  17.                 for(int j = i; j < 70; j += i) {  
  18.                         vis[j] = 1;  
  19.                 }  
  20.         }  
  21. }  
  22.   
  23. void init() {  
  24.         Exclu.clear();  
  25.         for(int i = 0; abs(p[i]) <= r; ++i) {  
  26.                 int cnt = Exclu.size();  
  27.                 for(int j = 0; j < cnt; ++j) {  
  28.                         if(abs(p[i] * Exclu[j]) <= 63) {  
  29.                                 Exclu.push_back(p[i] * Exclu[j]);  
  30.                         }  
  31.                 }  
  32.                 Exclu.push_back(p[i]);  
  33.         }  
  34.   
  35. }  
  36.   
  37. ll getNum(ll n) {  
  38.         if(n == 1) return 0;  
  39.         ll ans = n;  
  40.         for(int k : Exclu) {  
  41.                // +0.5为了保证精度;-1是暂时不包含1(因为当a=1时,a^b一定会等于1)    
  42.                ll tmp = (ll)pow(n + 0.5, 1.0/abs(k)) - 1;  
  43.                if(k < 0) {  
  44.                 ans -= tmp;  
  45.                }  
  46.                else {  
  47.                 ans += tmp;  
  48.                }  
  49.         }  
  50.         // 减去刚才没有包含在内的1  
  51.         return ans - 1;  
  52. }  
  53.   
  54. int main()  
  55. {  
  56.         ios::sync_with_stdio(false);  
  57.         int T;  
  58.         getPrime();  
  59.         cin >> T;  
  60.         ll ans, tmp;  
  61.         while(T--) {  
  62.                cin >> n >> r;  
  63.                init();  
  64.                ans = n;  
  65.                while(true) {  
  66.                 tmp = getNum(ans);  
  67.                 if(tmp == n)  
  68.                         break;  
  69.                 ans += n - tmp;  
  70.                }  
  71.                cout << ans << endl;  
  72.         }  
  73.         return 0;  
  74. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值