传送门
题意:给一个01串SSS,求一个等长的01串TTT
- SSS和TTT所有对应位置的子串最长不下降子序列长度(以下简称LIS\text{LIS}LIS)相同
- TTT中0的数量尽量多
∣S∣≤100000|S| \leq 100000∣S∣≤100000
对于一个01串SSS,我们称它是固定的,当且仅当不存在一个长度相同的01串TTT,它们所有对应位置的子串LIS\text{LIS}LIS相同(即修改任意一个位置都会改变LIS\text{LIS}LIS),并且规定空串是固定的。
- 两个固定的串拼起来仍然是固定的。如果修改了一个位置,根据定义,这个位置原来归属的串的LIS\text{LIS}LIS一定发生了变化。
- 一个固定的串0和1个数相等,LIS\text{LIS}LIS等于其长度的一半,即全选0或全选1。前面和下一条递归证明,边界为空串。后面由于一组01(见下一条)的1一定在0的前面,最多只有1的贡献。
- 一个固定的串前面添“1”,后面添“0”后仍然固定。和上一条递归证明,修改中间同理,修改两边一定会增加1。
我们在原串中删除所有极大的固定子串,由于没有“10”,所以剩下的一定是“00000……11111”
由定义,固定子串是不能修改的
【解法一】
我们发现这玩意就是括号匹配
用个栈维护一下,得到剩下的字符
然后把后面的一坨1都改成0。显然不能改更多的。
这样对于任意一个子串,把它的极大固定子串挖出来,由于后缀的“1”可能改成了“0”,把影响的段改成“全选0”后LIS\text{LIS}LIS不会变化,可以保证合法。
【解法二】
结论:某个1可以改为0,当且仅当修改后整个串的LIS\text{LIS}LIS不变。
其实本质是相同的。如果某个位置的1在某个固定子串中,显然修改会改变这个子串的LIS\text{LIS}LIS,并且会改变原串的LIS\text{LIS}LIS。否则对LIS\text{LIS}LIS不会产生影响。
倒着DP一下即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#define MAXN 100005
using namespace std;
char s[MAXN];
int pre0[MAXN],suf1[MAXN],dp[MAXN];
int main()
{scanf("%s",s+1);int n=strlen(s+1);for (int i=1;i<=n;i++) pre0[i]=pre0[i-1]+(s[i]=='0');for (int i=n;i>=1;i--) suf1[i]=suf1[i+1]+(s[i]=='1');for (int i=n;i>=1;i--) dp[i]=(s[i]=='1'? max(suf1[i],dp[i+1]):dp[i+1]+1);int now=0;for (int i=1;i<=n;i++)if (s[i]=='0'||now+1+dp[i+1]<=dp[1]) putchar('0'),++now;else putchar('1');return 0;
}