P1106 学习笔记
44 分做法
拿到题目很容易想到把 \(k\) 个最大值全部删掉,于是你写出了如下代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
string s;
int k;
getline(cin, s);
cin >> k;
while (k > 0){
int maxn = -1;
for (int i = 0; i < s.size(); i++)
maxn = max(maxn, (int)(s[i] - '0'));//找最大值
for (int i = 0; i < s.size(); i++)
if ((int)(s[i] - '0') == maxn){
s.erase(i, 1);
break;
}//删最大值
k--;
}
cout << s;
return 0;
}
当然,这是错误的。
100 分做法
为什么是错的呢?我们可以举出如下反例,例如当 \(n=1319,k=1\) 时,按照上面的 伪 做法,删去 \(9\) 时得到的是 \(131\),而删掉 \(3\) 可以得到更小的 \(119\)。
怎么办呢?让我们好好回想一下 小学一年级就学过的 自然数比较法则,是从第一位开始逐位比较,与上面的比较谁的最大值最小完全不符。
我们注意到 \(1<3,3>1\),我们称 \(3\) 为此数列的峰值,所以我考虑删掉峰值处的数。
这个做法的原理就是我们熟(mo)悉(sheng)的自然数比较法则。我们就可以轻松地写出 AC 代码。
注意前导零。
#include <bits/stdc++.h>
using namespace std;
string s;
int main() {
int k;
cin >> s;
cin >> k;
while (k){
int sum = 0;
for (int i = 0; s[i] <= s[i + 1]; )
sum++, i++;//找峰值
s.erase(sum, 1);//删
k--;
}
while (s[0] == '0' && s.size() > 1)
s.erase(0, 1);//前导零
cout << s;
return 0;
}

浙公网安备 33010602011771号