【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;
}

posted @ 2025-10-10 09:14  bz02_2023f2  阅读(1)  评论(0)    收藏  举报  来源