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;
}
posted @ 2026-02-02 19:14  constexpr_ll  阅读(0)  评论(0)    收藏  举报