一本通-1333:【例2-2】Blah数集(优先级队列模拟)¶
【题目描述】 大数学家高斯小时候偶然间发现一种有趣的自然数集合Blah,对于以a为基的集合Ba定义如下:
1 2 3 4 5 |
|
现在小高斯想知道如果将集合Ba中元素按照升序排列,第N个元素会是多少?
【输入】 输入包括很多行,每行输入包括两个数字,集合的基a(1≤a≤50))以及所求元素序号n(1≤n≤1000000)。
【输出】 对于每个输入,输出集合Ba的第n个元素值。
【输入样例】 1 100 28 5437
【输出样例】 418 900585
#include <bits/stdc++.h>
using namespace std;
long long a, k;
vector<long long> seq(1000005);
long long solve()
{
int rear = 2;
seq[1] = a;
int two = 1, three = 1;
while (rear <= k) {
long long tmp1 = seq[two] * 2 + 1;
long long tmp2 = seq[three] * 3 + 1;
long long res = min(tmp1, tmp2);
if (tmp1 < tmp2) ++two;
else ++three;
if (res == seq[rear - 1]) continue;
else seq[rear++] = res;
}
return seq[k];
}
int main()
{
std::ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
while (cin >> a >> k) {
cout << solve() << endl;
}
return 0;
}
这道题和洛谷-P1323 删数有一些类似,在洛谷的题目里我们使用优先级队列来生成数据,这里如果也使用优先级队列,会发现结果不一致。在洛谷里面,我们没有去考虑会不会产生重复数字的情况,而本题的集合里面是不能包含重复数字的。不能包含重复数字,且描述的是有序集合,第一个想到的是使用set
,每次用迭代器取出首元素,然后再插入两个新元素。但是在本题使用set
会超时。
除了第一个元素外,集合的一部分数字可以表示成2 * x + 1
,一部分可以表示成 3 * x + 1
,就有些类似队列的味道。每次取出两个集合最小的两个数字比较,取出最小的,但是注意要和队列的尾端去比较看是否重复。