Problem
卡拉兹 Callatz 猜想已经在 1001 中给出了描述。在这个题目里,情况稍微有些复杂。
当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数。例如对 \(n = 3\) 进行验证的时候,我们需要计算 3,5,8,4,2,1,则当我们对 \(n = 5\), \(8\), \(4\), \(2\) 进行验证的时候,就可以直接判定卡拉兹猜想的真伪,而不需要重复计算,因为这 4 个数已经在验证3的时候遇到过了,我们称 5,8,4,2 是被 3 『覆盖』的数。我们称一个数列中的某个数 \(n\) 为『关键数』,如果 \(n\) 不能被数列中的其他数字所覆盖。
现在给定一系列待验证的数字,我们只需要验证其中的几个关键数,就可以不必再重复验证余下的数字。你的任务就是找出这些关键数字,并按从大到小的顺序输出它们。
Input Format
每个测试输入包含 1 个测试用例,第 1 行给出一个正整数 \(K\) \((< 100)\),第 2 行给出 \(K\) 个互不相同的待验证的正整数 \(n\) \((1 < n \le 100)\) 的值,数字间用空格隔开。
Output Format
每个测试用例的输出占一行,按从大到小的顺序输出关键数字。数字间用 1 个空格隔开,但一行中最后一个数字后没有空格。
Sample Input
6
3 5 6 7 8 11
Sample Output
7 6
Solution
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
void hailStone(int x, map<int, bool>& covered) {
while (x != 1) {
if (x % 2 == 0)
x /= 2;
else
x = (3 * x + 1) / 2;
covered[x] = true;
}
}
int main() {
int n;
cin >> n;
vector<int> a(n);
map<int, bool> covered;
for (int i = 0; i < n; i++) {
cin >> a[i];
covered[a[i]] = false;
}
for (int i = 0; i < n; i++)
hailStone(a[i], covered);
vector<int> result;
for (auto walker : covered) {
if (!walker.second)
result.push_back(walker.first);
}
sort(result.rbegin(), result.rend());
for (int i = 0; i < result.size(); i++) {
cout << result[i];
if (i < result.size() - 1)
cout << " ";
}
cout << endl;
return 0;
}