题目链接:https://codeforces.com/contest/933/problem/A
昨晚睡觉前时看到的题目,感觉是个dp,便收藏了
题目大意:
给出一个由12和组成的序列,现在你可以翻转一个区间,询问翻转一个区间后,最长的不下降子序列是多少?
题目思路:
经典区间翻转问题..
刚开始读错题目,以为不只有1和2,想了好一会
那么既然只有1 和 2
那么就可以用3种状态表示最终最长不下降子序列的的形式:
1.11 - > 1 1 1 1 1
2.01 - > 0 0 0 1 1
3.00 - > 0 0 0 0 0
其次,首先预处理一下,前缀pre 3种状态的长度 与 后缀 3种状态的长度
最后,枚举每一个右端点,然后根据枚举前缀3种长度时的转移,去维护01 11 00
对于每一个能拼接的状态,都能求一个最大值即可
Code:
/*** keep hungry and calm CoolGuang! ***/
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define d(x) printf("%lld\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e17;
const ll maxn = 2e5+700;
const int mod= 1e9+7;
const int up = 1e9;
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
int pre[maxn][4],suf[maxn][4];
int num[maxn];
int main(){
read(n);
for(int i=1;i<=n;i++) read(num[i]);
for(int i=1;i<=n;i++){
for(int k=0;k<3;k++) pre[i][k] = pre[i-1][k];
if(num[i] == 1) pre[i][0] ++;///00
else{
pre[i][2] ++;///11
if(pre[i-1][0]) pre[i][1] = max(pre[i][1],pre[i-1][0]+1);///01
if(pre[i][1]) pre[i][1] = max(pre[i][1],pre[i-1][1]+1);///01
}
}
for(int i=n;i>=1;i--){
for(int k=0;k<3;k++) suf[i][k] = suf[i+1][k];
if(num[i] == 2) suf[i][2]++;///11
else{
suf[i][0]++;
if(suf[i+1][1]) suf[i][1] = max(suf[i][1],suf[i+1][1]+1);
if(suf[i+1][2]) suf[i][1] = max(suf[i][1],suf[i+1][2]+1);
}
}
ll ans = 0;
for(int i=1;i<=n;i++){
ll a = 0,b = 0,c = 0;
for(int k=i;k>=1;k--){
if(num[k] == 1){
b++;
ll tempc = c;
if(a) c = max(c,a+1ll);
if(tempc) c = max(c,tempc+1);
}else a++;
///00
ans = max(ans,pre[k-1][0]+a+max(suf[i+1][0],max(suf[i+1][1],suf[i+1][2])));
///01
ans = max(ans,pre[k-1][0]+c+suf[i+1][2]);
///11
ans = max(ans,max(pre[k-1][0],max(pre[k-1][1],pre[k-1][2]))+b+suf[i+1][2]);
}
}
printf("%lld\n",ans);
return 0;
}
/***
****/