题目链接:http://codeforces.com/contest/1204/problem/D2

题目是给定一个01字符串,让你尽可能多地改变1变为0,但是要保证新的字符串,对任意的L,R使得Sl,Sl+1,Sl+2...Sr的最长不递减子序列长度保持不变,求新的串s。

dp思路,从前往后遍历串s。

1 . 遇到s[ i ] = 0 是不能改变的,因为从i到n的最长不递减子序列必定是以s[ i ] = 0为起点的,改变之后会减少长度。

2 . 遇到s[ i ] = 1。我们考虑如果变为0,首先从0到 i-1 的最长不递减子序列是不受到影响的,因为从0到 i 的最长不递减子序列必定是以s [ i ] = 1为结尾的,不影响0到i -1 的最长不递减子序列,那么在0到i区间内, 我们需要保证条件1:任意的x(0<x<i)到 i 最长不递减子序列不发生改变,这里只要保证0到 i 的最长不递减子序列不变即可,任意的x(0<x<i)到 i 的最长不递减子序列就不会改变,因为0到x不会因为s[ i ]的变化受到影响,所以只要0到 i 的最长不递减子序列不发生改变,则x到 i 也不会改变。如果此时将s[ i ] 从1变成 0,要要0到 i 的最长不递减子序列不变,只有是以s[ i ] = 0为结尾的最长不递减子序列(原因上述有提到)的长度不变才可以,以s[ i ] = 0为结尾只能是一组0000...00,中间不能穿插1,所以其等价条件就是zeros + 1 == LIS1[ i ] (zeros表示从0到i中0的个数,LIS1表示0到i的最长不递减子序列),这里便满足条件1了。

需要满足的条件2:既然0到 i 已经保证,那么 i 到 n也是同样的道理,s[ i ] 由1变为0,此时 i 到n的最长不递减子序列势必是以s[ i ] = 0 为起点,其长度可以表示为LIS2[ i + 1 ]+1    // ( LIS2[ i +1 ] 表示i + 1 到n的最长不递减子序列) //。如果改变之前的最长不递减子序列是以s [ i ] = 1为起点,改变之后仍然以s[ i ] 为起点的话就没有问题,如果改变之前不是以S[ i ]为起点,改变之后从i到的n的最长不递减子序列必定会增加,因为i到n最长不递减子序列不管是以0为起点还是1为起点,当s[ i ] = 0时,肯定会与其拼接上,长度会+1。以上的等价条件就转化为 LIS2[ i ] == LIS2[ i +1 ] +1

满足以上两个条件的情况下,就可以使s[ i ] = 1变为0。

PS:在求解最长不递减子序列的过程中,如果用O(n^2)的算法对hard version会超时,easy version可以过。所以只能选择nlogn复杂度的算法。但是对于求LIS2[ i ] (i到n的最长不递减子序列),我没有想到相对简单的办法,因为不会lower_bound()的重载,所以只能选择较为麻烦的方法(具体看代码), 如果哪位朋友有更简便的做法可以留言一起交流一下。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#define maxn 100005
using namespace std;
int LIS1[maxn],LIS2[maxn],ones[maxn];
char low1[maxn],low2[maxn];//low[i]数组记录长度为i的最长不递减子序列结尾最小的元素
string s;
int zeros = 0,ans = 1;
int main(){
cin>>s;
LIS1[0] = 1,low1[1] = s[0];
for(int i = 1;i<s.length();i++){
if(s[i] >= low1[ans]){
low1[++ans] = s[i];
}
else{
int k = upper_bound(low1,low1 + ans + 1,s[i]) - low1 ;
low1 [k] = s[i];
}
LIS1[i] = ans;
}//用nlogn时间复杂度求从左到右求最长上升子序列 int cnt_one = 0;//从右到左记录1的个数
if(s[s.length() -1] == '1'){
cnt_one++;
}
ans = 1,LIS2[s.length() -1] = 1,low2[ans] = s[s.length()-1];
for(int i = s.length() -2;i>=0;i--){
if(s[i]<= low2[ans]){
low2[++ans] = s[i];//low2[++ans]中++ans长度的最长不递减子序列起始值改为s[i]
}
if(s[i] == '1'){
cnt_one++;//ans1记录1的个数
}
if(ans == cnt_one){
low2[ans] = '1';//贪心策略,如果此时ans和 cnt相等,
//把长度为 ans 的从左到右最长不递减子序列的起始值改为1,方便后续可以拼接0
}
LIS2[i] = ans;
}//从右到左,求i到s.length()-1的最长不递减子序列
for(int i = 0;i<s.length() ;i++){
if(s[i] == '0'){
zeros++;//前i个元素中0的个数
}
if(s[i] == '1'){
if(zeros + 1 == LIS1[i] && LIS2[i] == LIS2[i+1] + 1){
s[i] = '0';//如果两者相等,则可以把1改为0
zeros++;
}
}
}
cout<<s;
return 0;
}

Codeforces 1204D2. Kirk and a Binary String (hard version) (dp思路)的更多相关文章

  1. D2. Kirk and a Binary String (hard version) D1 Kirk and a Binary String (easy version) Codeforces Round #581 (Div. 2) (实现,构造)

    D2. Kirk and a Binary String (hard version) time limit per test1 second memory limit per test256 meg ...

  2. D1. Kirk and a Binary String (easy version)

    D1. Kirk and a Binary String (easy version) 01串找最长不降子序列 给定字符串s,要求生成一个等长字符串t,使得任意l到r位置的最长不降子序列长度一致 从后 ...

  3. Codeforces 1204D Kirk and a Binary String - 数学

    题目传送门 传送门 群除我均会猜结论/找规律,sad.... 以下内容只保证代码能过system test,证明应该都是在纯口胡 约定下文中的$LIS$表示最长不下降子序列. 定义$zero(s)$表 ...

  4. 01串LIS(固定串思维)--Kirk and a Binary String (hard version)---Codeforces Round #581 (Div. 2)

    题意:https://codeforc.es/problemset/problem/1204/D2 给你一个01串,如:0111001100111011101000,让你改这个串(使0尽可能多,任意 ...

  5. Codeforces 1107 E - Vasya and Binary String

    E - Vasya and Binary String 思路:区间dp + 记忆化搜索 转移方程看上一篇博客. 代码: #pragma GCC optimize(2) #pragma GCC opti ...

  6. Codeforces1107E Vasya and Binary String 记忆化dp

    Codeforces1107E 记忆化dp E. Vasya and Binary String Description: Vasya has a string \(s\) of length \(n ...

  7. CF1204D Kirk and a Binary String

    题目链接 problem 给出一个长度为\(n(n\le 10^5)\)的只包含01的字符串.把尽可能多的1变为0,使得对于所有的\(l \in [1,n],r\in [l,n]\),区间\([l,r ...

  8. [CF1107E]Vasya and Binary String【区间DP】

    题目描述 Vasya has a string s of length n consisting only of digits 0 and 1. Also he has an array a of l ...

  9. 2019牛客多校第三场B-Crazy Binary String(前缀和+思维)

    Crazy Binary String 题目传送门 解题思路 把1记为1,把0记为-1,然后求前缀和,前缀和相等的就说明中间的01数一样.只要记录前缀和数值出现的位置即可更新出答案. 代码如下 #in ...

随机推荐

  1. python django项目的搭建及初始配置

    1.创建项目并创建应用 django-admin startproject my_project # 创建项目python manage.py startapp my_app # 创建应用 1.1 项 ...

  2. Android 基础知识 -- BroadcastReceiver

    BroadcastReceiver 广播,是一种事件传递机制,可以跨应用进行事件传递(系统级). 在使用广播的时候,不宜添加过多的逻辑或者耗时(广播内不允许开辟线程)操作,超过10秒,导致ANR 1 ...

  3. IDAE打包WEB项目 WAR Eclipse转IDEA项目

    接下来这里只说WEB项目打包,相信大多数都是用的WEB项目吧,关于打包WAR,真的很头痛,网上说的试了好好次都不行. 后来懂了之后,真的很简单好么,分享给大家   不要多走弯路了. 注意:   如果你 ...

  4. SendMessage模拟按键所需的虚拟键码

    Virtual-Key Codes The following table shows the symbolic constant names, hexadecimal values, and mou ...

  5. b站德云社相声合集

    每天都做德云小可爱呀 郭德纲于谦相声合集搜索: 75314217.75079477 62444678.60874866 60745041.60514509 之前在喜马拉雅上面听过,部分高清的要会员,只 ...

  6. maven-设置aliyun远程库

    maven默认的远程库下载起来非常慢,习惯改成aliyun的库. 一.修改maven配置 打开maven配置文件setting.xml,改mirror <mirrors> <mirr ...

  7. vjudge Lake Counting 搜索 水池 8方向

    原题链接https://vjudge.net/contest/331118#problem/A 题目: 现在有一个M*N的方阵,每个格子里面是.或者W,点代表水,然后如果在这个点的周围,即8个方向内还 ...

  8. windows 环境变量%SystemDrive%和%SystemRoot%、%AppData%、%LocalAppData%、%TEMP% 等简写

    windows 环境变量%SystemDrive% 和%SystemRoot%.%AppData%.%LocalAppData%.%TEMP% 等简写 假设操作系统安装在 C: 盘 %SYSTEMRO ...

  9. python xlrd 模块(获取Excel表中数据)

    python xlrd 模块(获取Excel表中数据) 一.安装xlrd模块   到python官网下载http://pypi.python.org/pypi/xlrd模块安装,前提是已经安装了pyt ...

  10. 剑指offer 39. 是否为平衡二叉树

    39. 是否为平衡二叉树 题目描述 输入一棵二叉树,判断该二叉树是否是平衡二叉树 任意结点的左右子树高度差不大于1就是平衡二叉树. C++解法 class Solution { public: boo ...