【2025.10.10NOIP】最长不下降子序列(sequence)题解
题目描述
小 W 有一个长度为 n 的序列 a1,a2,⋯,an,且 ai 的取值只可能为 1 或 2。
现在,你可以任意选择该序列的一个区间进行翻转操作,但你只能翻转一次。
小 W 希望执行操作之后,整个序列的最长不下降子序列长度最大。请你求出这个最大值。
输入
从文件 sequence.in 中读入数据。
输入的第一行为一个正整数 n。
接下来一行 n 个正整数 a1,⋯an。
输出
输出到文件 sequence.out 中。
一行一个整数表示最长不下降子序列长度。
样例数据
输入 #1 复制
4 1 2 1 2
输出 #1 复制
4
输入 #2 复制
10 1 1 2 2 2 1 1 2 2 1
输出 #2 复制
9
数据范围限制
对于前 10% 的数据,保证 ai=1。
对于前 30% 的数据,保证 n≤50。
对于前 70% 的数据,保证 n≤2000。
对于所有数据,保证 1≤n≤106,ai∈{1,2}。
提示
样例解释 #1
翻转区间 [2,3],整个序列变为 1,1,2,2,自然答案是 4。
样例解释 #2
翻转区间 [3,7]。
思路
DP即可。
代码见下
#include<bits/stdc++.h>
using namespace std;
long long n,a[100006],b[100006][2],lk[100006],kl[100006],op=0;
int main(){
freopen("sequonce.in","r",stdin);
freopen("sequonce.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int j=1;j<=n;j++){
b[j][0]=b[j-1][0];
if(j==1){
b[j][0]=0;
}
if(a[j]==1){
b[j][0]++;
}
//cout<<a[i]<<" ";
}
for(int j=n;j>=1;j--){
b[j][1]=b[j+1][1];
if(j==n){
b[j][1]=0;
}
if(a[j]==2){
b[j][1]++;
}
}
// lk=0;
// kl=0;
// for(int j=1;j<=n;j++){
// lk=max(lk,b[j][0]+b[j][1]);
// }
// op=max(op,lk+kl);
for(int i=n-1;i>=1;i--){
if(a[i+1]==2){
kl[i]=max(kl[i+1],b[i+1][1]);
}
else{
kl[i]=kl[i+1]+1;
}
}
for(int i=1;i<=n;i++){
if(a[i]==2){
lk[i]=lk[i-1]+1;
}
else{
lk[i]=max(lk[i-1],b[i][0]);
}
}
for(int i=1;i<=n;i++){
op=max(op,lk[i]+kl[i]);
}
op=max(op,b[n][0]);
op=max(op,b[1][1]);
cout<<op<<endl;
return 0;
}

浙公网安备 33010602011771号