[题解]UVA11549 Calculator Conundrum
前言:首先感谢 @ Kisaragi_77 大佬为我提供的思路。
思路
这是我们今天模拟赛的一道题,拿到这道题后,一点思路都没有,在老师的指导下,想到了用 map ,但是并没有写出来。
考试后,我看了一下题解,发现 @ Kisaragi_77 大佬的思路非常清晰。
具体做法呢,就是用一个 set 来实现。
不会用 set 来看着这里
先写一个死循环,再循环中判断新算出来的这个数是否在 set 中出现过,如果出现过,说明有一个循环,不会再出现新的值了,就输出 set 最后一个值。
我来举一个例子吧!
当 \(n = 1,k = 6\) 时,计算器会依次显示 \(6,3,9,8,6,3...,\) 这个时候你会发现在第二个 \(6,3\) 开始后都在重复之前的 \(6,3,9,8\)
事实证明,只要出现了循环就可以结束了
但,为什么是输出最后一个值呢?
最主要的原因便是:set 在存储和删除中,都是会保序的,所以 set 中储存过的数中最后一个数必定时最大的。
Code
#include <bits/stdc++.h>
#define int long long//防止有爆 int 范围,这个方法需要把值函数前面的 int 改成 signed
using namespace std;
int T;//组数
int n,k;//见题目
int f(int x){//用来求一个数的前 n 位的函数
int p = pow(10,n);//前 n 位便有至少有 pow(10,n)便于我们对返回前 n 为的值
while (x >= p) x /= 10;//如果当前的值大于等于 n 位数的最小值便要除以 2
return x;//最后返回 x
}
signed main(){
cin >> T;
while (T--){
set<int> s;//定义一个 set
cin >> n >> k;//输入 n,k
s.insert(f(k));//将 f(k) 插入到 s 中,因为题目中说了他在计算器上输入了一个 k,并且防止 k 大于 n 位数,所以我们要向 s 中插入 f(k)
while (1){//先写一个死循环
int t = f(k * k);//算出新的数,并对其使用 f 函数
if (s.count(t)){//如果先算出的数在 s 中出现过了,那么就说明已经出现了循环,不可能再出新的数了
printf("%lld\n",*(--s.end()));//输出最后一个数
break;//结束循环
}
else s.insert(t);//否则将新算出的数插入到 s 中
k = t;//将 k 更新成为新数
}
}
return 0;
}

浙公网安备 33010602011771号