子序列-反转区间求最长不下降子序列

简介: 题目描述小Z有一个01序列A=(A1,A2,A3,…,An)。他可以进行一次操作:选择一个区间L,R将其反转。例如,对于序列A=(1,0,0,1,1),当L=2,R=4时,原序列将变为(1,1,0,0,1)。小Z希望:通过这一次反转操作,使得这个序列的最长不下降子序列的长度尽可能的大,并想让你输出这个最大值。一个序列的不下降子序列定义为:对于一个序列(p1,p2,…,pk)满足1≤p1<p2<…<pk≤n(n≤819200)且Ap1≤Ap2≤…≤Apk。则序列(Ap1,Ap2,…,Apk)为不下降子序列,其中k为这个不下降子序列的长度。输入一行一个01字符串,表示序列A

题目描述


小Z有一个01序列A=(A1,A2,A3,…,An)。他可以进行一次操作:选择一个区间L,R将其反转。

例如,对于序列A=(1,0,0,1,1),当L=2,R=4时,原序列将变为(1,1,0,0,1)。

小Z希望:通过这一次反转操作,使得这个序列的最长不下降子序列的长度尽可能的大,并想让你输出这个最大值。

一个序列的不下降子序列定义为:对于一个序列(p1,p2,…,pk)满足1≤p1<p2<…<pk≤n(n≤819200)且Ap1≤Ap2≤…≤Apk。则序列(Ap1,Ap2,…,Apk)为不下降子序列,其中k为这个不下降子序列的长度。


输入


一行一个01字符串,表示序列A


输出


一行一个正整数,表示最长不下降子序列长度的最大值。


样例输入


00111001101


样例输出


10


提示


一种最优策略为:反转区间[3,7],数列将变为(0,0,0,0,1,1,1,1,1,0,1) ,其最长不下降子序列的长度为10。


在一开始的时候以为反转某一段区间之后,只会影响反转的这一块中0或1的数量与前一段或后一段的0或1的数量

然后统计出来0或1的块的大小,只反转1…10…0这样的区间,其实是错的

答案会影响四段


wrong_code:

记录反转了这一块后前面0的个数与后面1的数量思路其实是错的

int n,k;
int a[maxn];
struct node{
    int id;
    int ct;
}b[maxn];
int main()
{
    string s;
    cin >> s;
    n = s.size();
    s = "#" + s;
    int cnt = 0;
    int t = 0;
    int bak1 = 0;
    for(int i=1;i<=n;i++){
        ++ t;
        if(i == n || s[i] != s[i+1]){
            b[++cnt].id = s[i] - '0';
            b[cnt].ct = t;
            t = 0;
            if(s[i] == '1') bak1 += b[cnt].ct;
        }
    }
    /*for(int i=1;i<=cnt;i++){
        cout << b[i].id<<' '<<b[i].ct<<endl;
    }*/
    /// debug(bak1);
    if(cnt == 1 || cnt == 2){
        cout << n <<endl;
        return 0;
    }
    int pre0 = 0;
    int ans = 0;
    b[0].id = 0,b[0].ct=0;
    for(int i=1;i<cnt;i++){
        if(b[i-1].id == 0) pre0 += b[i-1].ct;
        else bak1 -= b[i-1].ct;
        ans = max(ans,bak1 + pre0);
        if(b[i].id == 1 && b[i+1].id == 0){
            ans = max(ans,pre0 + b[i+1].ct + bak1);
            /*debug(pre0);
            debug(b[i+1].ct);
            debug(bak1);*/
            // cout << pre0 + b[i+1].ct + bak1 <<endl;
        }
    }
    cout << ans <<endl;
    return 0;
}
/**************************************************************
    Problem: 13769
    Language: C++
    Result: 答案错误
****************************************************************/


ac_code:


int main()
{
    string s;
    cin >> s;
    n = s.size();
    s = "#" + s;
    int t1,t2,t3,res;
    t1 = t2 = t3 = res = 0;
    for(int i=1;i<=n;i++){
        if(s[i] == '0'){
            ++ t1;
            t2 = max(t1,t2);
            t3 = max(t2,t3 + 1);
            res = max(res,t3);
        }else{
            t2 = max(t1,t2 + 1);
            t3 = max(t2,t3);
            res = max(t3,res + 1);
        }
    }
    cout << res <<endl;
    return 0;
}
/**************************************************************
    Problem: 13769
    Language: C++
    Result: 正确
    Time:40 ms
    Memory:15588 kb
****************************************************************/


追更:

其实这道题和acwing上面,这道题是一样的


4661eea497f943fe80dc7a8efba36209.png

应该考虑答案影响的四段


最优质一定是在00000111110000011111

这种情况下的

我们用s1记录00000的最长长度

用s2 记录0000011111的最长长度

用s3 记录000001111100000的最长长度

用s4 记录00000111110000011111的最长长度

最终答案就是s3,s4中最大值

O(n)


该题code:


#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int main()
{
    int n; cin >> n;
    int s1 = 0,s2 = 0,s3 = 0,s4 = 0;
    for(int i=1;i<=n;i++){
        int x;scanf("%d",&x);
        if(x == 1){
            ++ s1;
            s3 = max(s2 + 1,s3 + 1);
        }else{
            s2 = max(s1 + 1,s2 + 1);
            s4 = max(s3 + 1,s4 + 1);
        }
    }
    cout << max(s3,s4) <<endl;
    return 0;
}






目录
相关文章
|
算法 Java C语言
【数据结构】后缀(逆波兰)表达式的计算以及中缀转后缀的方法
【数据结构】后缀(逆波兰)表达式的计算以及中缀转后缀的方法
2003 1
|
JSON 算法 安全
JWT、JWE、JWS 、JWK 都是什么鬼?还傻傻分不清?
JWT 相信很多小伙伴都知道,JSON Web Token,如果在项目中通过 jjwt 来支持 JWT 的话,可能只需要了解 JWT 一个概念即可,但是现在很多时候我们可能不是使用 jjwt,而是选择 nimbus-jose-jwt 库,此时就有可能接触到一些新的概念,如 JWE、JWS。那么 JWE、JWS 以及 JWT 之间是什么关系呢?
3403 0
JWT、JWE、JWS 、JWK 都是什么鬼?还傻傻分不清?
|
存储 小程序 Linux
【Linux从入门到精通】C语言模拟实现进度条小程序
在Linux下,我们安装软件时会经常看到进度条,来告知我们安装的进度。我们不妨自己模拟实现一个进度条,看看其中的细节。模拟实现进度条并不困难,但其中的细节我们又不可忽视。本篇文章会对模拟实现进度条进行详解。
417 1
|
Ubuntu 数据安全/隐私保护
ubuntu默认root密码
安装完Ubuntu后忽然意识到没有设置root密码,不知道密码自然就无法进入根用户下。到网上搜了一下,原来是这麽回事。Ubuntu的默认root密码是随机的,即每次开机都有一个新的root密码。我们可以在终端输入命令 sudo passwd,然后输入当前用户的密码,enter,终端会提示我们输入新的密码并确认,此时的密码就是root新密码。
17858 1
|
数据采集 人工智能 缓存
GitHub图片加载不出来解决方案(超详细图文教程)
GitHub图片加载不出来解决方案(超详细图文教程)
4010 0
【数字IC手撕代码】Verilog偶数分频|题目|原理|设计|仿真(二分频,四分频,六分频,八分频,偶数分频及特殊占空比)
【数字IC手撕代码】Verilog偶数分频|题目|原理|设计|仿真(二分频,四分频,六分频,八分频,偶数分频及特殊占空比)
【数字IC手撕代码】Verilog偶数分频|题目|原理|设计|仿真(二分频,四分频,六分频,八分频,偶数分频及特殊占空比)
|
存储 Unix Linux
路径中的斜杠/反斜杠\双斜杠以及常用绝对路径与相对路径知识
路径中的斜杠/反斜杠\双斜杠以及常用绝对路径与相对路径知识
762 0
路径中的斜杠/反斜杠\双斜杠以及常用绝对路径与相对路径知识
|
数据采集 搜索推荐 JavaScript
超详细Hexo+Github博客搭建小白教程(二)
首先要了解一下我们搭建博客要用到的框架。Hexo是高效的静态站点生成框架,它基于Node.js。通过Hexo,你可以直接使用Markdown语法来撰写博客。相信很多小伙伴写工程都写过README.md文件吧,对,就是这个格式的!写完后只需两三条命令即可将生成的网页上传到你的github上,然后别人就可以看到你的网页啦。是不是很简单?你无需关心网页源代码的具体细节,你只需要用心写好你的博客内容就行。
411 0
超详细Hexo+Github博客搭建小白教程(二)