To_Heart—题解——「泉州一中基地赛20180519」第三题

描述

题目描述

小 A 有一个长度为 n n n 的序列 a a a,满足 a a a 中的所有元素都是 1 1 1 2 2 2

你想要篡改这个序列。你可以任意选择原序列的一段区间 [ l , r ] [l,r] [l,r],并将 a l , a l + 1 , ⋯   , a r a_l, a_{l+1},\cdots, a_r al,al+1,,ar 翻转。为了不被发现,你只能执行该操作至多一次。

你希望最大化操作之后序列最长不下降子序列的长度,请求出这个值。

序列 a a a 的一个不下降子序列是一个下标序列 p 1 , p 2 , ⋯   , p k p_1, p_2,\cdots, p_k p1,p2,,pk,满足 p 1 < p 2 < ⋯ < p k p_1 < p_2 <\cdots < p_k p1<p2<<pk a p 1 ≤ a p 2 ≤ ⋯ ≤ a p k a_{p_1} \le a_{p_2} \le \cdots \le a_{p_k} ap1ap2apk 。定义它的长度为 k k k

输入格式

第一行一个整数 n n n,表示序列的长度。

第二行 n n n 个用空格隔开的正整数,描述了序列 a a a

输出格式

输出一行一个整数,表示操作之后序列最长不下降子序列长度的最大值。

样例

样例 1 输入

4
1 2 1 2

样例 1 输出

4

样例 2 输入

10
1 1 2 2 2 1 1 2 2 1

样例 2 输出

9

题解

题解

大思路:DP

不要问为什么不是贪心,问就是贪不出来

dp[i][0] 前i个中最后以2结尾的最大值,且交换过

dp[i][1] 1的数量

dp[i][2] 前i个中最后以2结尾的最大值,且未交换过;

dp[i][3] 前i个中最后以1结尾的最大值,(交换1次);

1.a[i]==1

dp[i][0] = dp[i - 1][0];                         	//末尾不是2,无法改变;
dp[i][1] = dp[i - 1][1] + 1;                     	//是1,所以1的数量加1;
dp[i][2] = dp[i - 1][2];                         	//末尾不是2,无法改变 ;
dp[i][3] = Max(dp[i - 1][2], dp[i - 1][3]) + 1;		

对于dp[i][3]的状态转移方程的解释:

第一种,dp[i-1][2]+1;

举个例子:

2 1 1 1 1 

此时可以转换为:

1 2 1 1 1

所以当前值为1时,可以直接接在后面进行转换;

第二种,dp[i-1][3]+1

因为如果前面已经进行过转换,那么我们只需要把它放在转换队列的最末尾即可,举个例子:

设此时的i为2,则dp[i][3]=1;

此时转换后的数列为:

1 2 1 1 1 	

当i=3时,根据原数列来看,我们可以将其转换为:

1 1 2 1 1 

所以dp[i][3]的一种转换方式为dp[i-1][3]+1;

2.a[i]==2

dp[i][0] = Max(dp[i - 1][0], dp[i - 1][3]) + 1;  		//是2,同下,但记录的却是变换过的
dp[i][1] = dp[i - 1][1];                        		//不是1,1的个数不变 ;
dp[i][2] = Max(dp[i - 1][2], dp[i - 1][1]) + 1;  		//是2,加1,因为没有进行过变换,所以可以在全是1的数列后面加1或在末尾是2的后面加1;
dp[i][3] = dp[i - 1][3];  								//是2,没必要进行变换

值得注意的是,我们无法保证最后的a[i]是1或者是2,所以我们无法保证最大的答案在dp[n][0]、dp[n][2]或dp[n][3]里面,所以比较一个最大值;

代码:

#include <bits/stdc++.h>
using namespace std;

#define Max(a, b) (((a) > (b)) ? (a) : (b))

int a[200005];
int dp[200005][15] = {
    
    };
int n;

int main() {
    
    
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
    
    
        scanf("%d", &a[i]);
    }
    for (int i = 1; i <= n; i++) {
    
    
        if (a[i] == 1) {
    
    
            dp[i][0] = dp[i - 1][0];                        
            dp[i][1] = dp[i - 1][1] + 1;                    
            dp[i][2] = dp[i - 1][2];                         
            dp[i][3] = Max(dp[i - 1][2], dp[i - 1][3]) + 1;  
        } 
		else {
    
    
            dp[i][0] = Max(dp[i - 1][0], dp[i - 1][3]) + 1;  
            dp[i][1] = dp[i - 1][1];                       
            dp[i][2] = Max(dp[i - 1][2], dp[i - 1][1]) + 1;  
            dp[i][3] = dp[i - 1][3];                       
    	}
	}
    printf("%d\n", Max(dp[n][0], dp[n][3]));
    return 0;
}

Guess you like

Origin blog.csdn.net/xf2056188203/article/details/109522279