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;
}