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} ap1≤ap2≤⋯≤apk 。定义它的长度为 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;
}