Codeforces 1204D2. Kirk and a Binary String (hard version) (dp思路)
题目链接: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思路)的更多相关文章
- 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 ...
- D1. Kirk and a Binary String (easy version)
D1. Kirk and a Binary String (easy version) 01串找最长不降子序列 给定字符串s,要求生成一个等长字符串t,使得任意l到r位置的最长不降子序列长度一致 从后 ...
- Codeforces 1204D Kirk and a Binary String - 数学
题目传送门 传送门 群除我均会猜结论/找规律,sad.... 以下内容只保证代码能过system test,证明应该都是在纯口胡 约定下文中的$LIS$表示最长不下降子序列. 定义$zero(s)$表 ...
- 01串LIS(固定串思维)--Kirk and a Binary String (hard version)---Codeforces Round #581 (Div. 2)
题意:https://codeforc.es/problemset/problem/1204/D2 给你一个01串,如:0111001100111011101000,让你改这个串(使0尽可能多,任意 ...
- Codeforces 1107 E - Vasya and Binary String
E - Vasya and Binary String 思路:区间dp + 记忆化搜索 转移方程看上一篇博客. 代码: #pragma GCC optimize(2) #pragma GCC opti ...
- Codeforces1107E Vasya and Binary String 记忆化dp
Codeforces1107E 记忆化dp E. Vasya and Binary String Description: Vasya has a string \(s\) of length \(n ...
- 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 ...
- [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 ...
- 2019牛客多校第三场B-Crazy Binary String(前缀和+思维)
Crazy Binary String 题目传送门 解题思路 把1记为1,把0记为-1,然后求前缀和,前缀和相等的就说明中间的01数一样.只要记录前缀和数值出现的位置即可更新出答案. 代码如下 #in ...
随机推荐
- unserialize():Error at offset 0 of 96 bytes是什么意思
数据库有个列是数组序列化后存到数据库的,取出来得反序列化, php想要把数组保存到数据库里,有两种序列化方式,分别是: //php系统序列化 $b = serialize($a); //序列化数 ...
- WPF DataGrid出现红框处理
当DataGrid属于单元格选中时出现红框,是因为WPF中DataGrid拥有默认的验证属性,如需关闭,请在DataGrid中加入以下属性: Validation.ErrorTemplate=&quo ...
- 初入python
初入python 一定要学好python 求1-100的和: i=1 s=0 while i<101: s=s+i i=i+1 print(s)
- 使用xshell
将选定的文本自动复制到剪贴板 并且 鼠标向右按钮定义为粘贴剪贴板内容
- Java中基本数据类型byte的溢出问题
Java中基本数据类型byte的溢出问题 问题源于:https://www.cnblogs.com/HuoHua2020/p/12326631.html 定义两个byte类型的数据,将其之和赋值给一个 ...
- 遇到的基础php函数、方法
0x01 PHP file() 函数 file() 函数把整个文件读入一个数组中. 数组中的每个元素都是文件中相应的一行,包括换行符在内. 实例: <?php print_r(file(&quo ...
- setTimeout(call,0)作用
setTimeout(call,0)作用 经常看到setTimeout延时0ms的javascript代码,感到很迷惑,难道延时0ms和不延时不是一个道理吗?后来通过查资料以及实验得出以下两个作用, ...
- 解决DFS Locations从Eclipse的Navigator中消失的问题
尝试了这篇博客https://blog.csdn.net/qq_40120951/article/details/85028976所说的解决办法,但对我没用. 最后是重新打开Map/Reduce解决的 ...
- [HAOI2011] Problem b - 莫比乌斯反演
复习一下莫比乌斯反演 首先很显然用一下容斥把它转化成求 \(ans=\sum_{i=1}^a \sum_{j=1}^b [{gcd(i,j)=d}]\) 我们可以定义 f(d) 和 F(d) 如下: ...
- normalization flow
from Eric Jang Normalizing flows transform simple densities (like Gaussians) into rich complex distr ...