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

简介: 题目描述小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;
}






目录
相关文章
|
3天前
|
机器学习/深度学习 算法 测试技术
【动态规划】【最长子序列】2901. 最长相邻不相等子序列 II
【动态规划】【最长子序列】2901. 最长相邻不相等子序列 II
|
3天前
|
算法 C++
【动态规划】【子序列除重】【C++算法】1987不同的好子序列数目
【动态规划】【子序列除重】【C++算法】1987不同的好子序列数目
|
8月前
【动态规划刷题 15】最长定差子序列&& 最长的斐波那契子序列的长度
【动态规划刷题 15】最长定差子序列&& 最长的斐波那契子序列的长度
|
3天前
代码随想录 Day44 动规12 LeetCode T300 最长递增子序列 T674 最长连续递增序列 T718 最长重复子数组
代码随想录 Day44 动规12 LeetCode T300 最长递增子序列 T674 最长连续递增序列 T718 最长重复子数组
44 0
|
3天前
最长连续不重复子序列
最长连续不重复子序列
16 1
|
3天前
|
算法 程序员 索引
【算法训练-动态规划 三】【双序列DP问题】最长重复子数组、最长公共子串、最长公共子序列、编辑距离
【算法训练-动态规划 三】【双序列DP问题】最长重复子数组、最长公共子串、最长公共子序列、编辑距离
70 0
|
7月前
|
算法
【学会动态规划】最长递增子序列的个数(28)
【学会动态规划】最长递增子序列的个数(28)
19 0
|
7月前
|
存储 算法
算法:滑动窗口解决连续区间子数组问题
算法:滑动窗口解决连续区间子数组问题
|
11月前
线性DP:最长上升(下降)子序列
线性DP:最长上升(下降)子序列
30 0
(区间dp最长上升子序列,最长下降子序列)
(区间dp最长上升子序列,最长下降子序列)
80 0