CF1204D2 二进制字符串(困难版)

1 CF1204D2 二进制字符串(困难版)

2 题目描述

时间限制 \(1s\) | 空间限制 \(256M\)

简单版和困难版的唯一区别是字符串的长度。

\(Kirk\) 有一个长度为 \(n\) 的二进制字符串(就是只包含 \(0\)\(1\) 的字符串)。他请你找出一个满足以下条件的长度为 \(t\) 的二进制字符串:

  • 对于任意的 \(l\)\(r, 1≤𝑙≤𝑟≤𝑛\),最长不下降子序列 \(s_l\)s\(_l\)\(_+\)\(_1...s_r\) 等于最长不下降子序列 \(t_l\)t\(_l\)\(_+\)\(_1...t_r\)
  • 字符串 \(t\) 中零的个数最大。

最长不下降子序列字符串 \(p\) 就是对于编号 \(i_1,i_2,...,i_k\),同时 \(𝑖_1<𝑖_2<…<𝑖_𝑘\),则 \(𝑝\)\(_𝑖\)\(_1\)≤𝑝\(_𝑖\)\(_2≤…≤𝑝\)\(_𝑖\)\(_𝑘\),字串的长度为 \(k\)

数据范围:二进制字符串长度不超过 \(10^5\)

3 题解

我们发现:如果一个 \(1\) 可以变成 \(0\),设它的位置为 \(i\),这个 \(1\) 肯定是 \(i\)\(n\) 这个区间的最长不下降子序列的唯一起点。如果不是最长子序列的唯一起点,那么一定存在一个以 \(0\) 为开头的最长不下降子序列,此时将当前的这个 \(1\) 改成 \(0\) 后就可以接在那个子序列前,使子序列长度变化,答案就不正确了。我们如何确定一个点是否是唯一起点呢?我们发现:如果某个 \(1\) 后面 \(1\) 的个数大于等于 \(0\),并且当前数后面紧跟着的 \(1\) 个数比 \(0\) 多,此时我们就可以确定最长不下降子序列以这个 \(1\) 为起点。

为了计算答案,我们只需要找到这个数后面在这个数与第一个 \(0\) 之间 \(1\) 的数量即可。如果这里 \(1\) 的数量大于 \(0\) 的数量,那么这个 \(1\) 就一定是最长不上升子序列的开头,这个 \(1\) 也就一定可以变成 \(0\)

4 代码(空格警告):

#include <iostream>
using namespace std;
int cnt0, cnt1;
string s;
int main()
{
    cin >> s;
    for (int i = s.length()-1; i >= 0; i--)
    {
        if (s[i] == '0') cnt0++;
        else
        {
            if (cnt1 >= cnt0) s[i] = '0';
            else cnt1++;
        }
    }
    cout << s;
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-03-11 21:04  David24  阅读(110)  评论(0编辑  收藏  举报