P1106 删数问题

P1106 删数问题
这题用双端队列做才是首选,贪心的思路很好理解,我们只有 k 次删除机会,每次删除都应该让前面的数尽可能地小,因为前面是高位,权重更高。

所以可以这样处理,维护一个单调不减的双端队列,遍历数组,若队列不为空且当前数小于队尾,而且有删除次数,则消耗一次删除次数弹出队尾(因为有了更小的选择),最后将当前数加到队尾。

遍历完成后可能会出现还有删除次数的情况(数组本身趋向于单调不减,遍历过程中很少满足弹出队尾的条件),这时进行相应次数的弹出队尾操作即可。

最后就是去除前导 0 和输出,下面列出的是本题的数据强化版U83355 删数问题【升级版】的AC代码,这个版本卡掉了 O(n^2) 的算法,我所知的可行的做法就是 O(nlogn)ST 表和本题解的 O(n)的做法。

#include <cstdio>
#include <cstring>
#include <deque>

using namespace std;

const int N = 5e5 + 5;
char a[N];
int n, k;

void solve() {
    scanf("%s%d", a, &k);
    n = strlen(a);
    
    deque<char> dq;
    for (int i = 0; i < n; i++) {
        while (!dq.empty() && a[i] < dq.back() && k) {
            dq.pop_back();
            k--;
        }
        dq.emplace_back(a[i]);
    }
    
    while (k--) dq.pop_back();
    while (!dq.empty() && dq.front() == '0') dq.pop_front();    // 去除前导 0
    
    if (dq.empty()) putchar('0');
    while (!dq.empty()) {
        putchar(dq.front());
        dq.pop_front();
    }
    putchar('\n');
}

int main() {
    int t; scanf("%d", &t);
    while (t--) solve();
    return 0;
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 前言 高级数据结构难点很多,而且小编接近一年没有碰过代码了,简书一天能发布的文章数目有限😂,所以今天决定爆肝一个晚...
    gzr666阅读 7,639评论 2 4
  • 目录介绍 3.0.0.1 在arrayList中System.arraycopy()和Arrays.copyOf(...
    杨充211阅读 3,157评论 0 1
  • 这里是剑指offer的一些笔记,有几道困难题没做,以后会不上,题解是按照做题序号来的。 数组中重复的数字 新建一个...
    周飞飞飞机阅读 3,077评论 0 0
  • 作为动态规划习题册 目录 1.luogu1417烹调方案[https://www.luogu.com.cn/pro...
    _NewMoon阅读 1,481评论 0 1
  • 1/4 往年真题 2/4 期末测验 课后选择题第一章:ACCAC第二章:ADBCB DDCAB第三章:D第四章:B...
    Du1in9阅读 10,519评论 1 48

友情链接更多精彩内容