1. 题目来源
2. 题目解析
线性 dp
、思维题。
首先看到了 1e6
的数据范围,故确定时间应该是 O(n)
的算法,故确定是个思维题,故从思考到放弃…
没看清题意,只有 1 或 2 出现,是子序列不是子串…
思路:
- 显然,最优解一定满足
1111222211112222
这种形式。 - 很明显,我们可以将其分为四段来看。
- 我们可以以
s1、s2、s3、s4
来分别表示从最优解起点到这四段末尾的长度。注意可以不连续,是子序列而不是子串。 - 同样,任意一段长度都可以是 0,
s1=1111
s2=1111 22222
s3=1111 22222 1111
,s3
的翻转s3=1111 1111 22222
s4=1111 22222 1111 2222
,s4
的翻转s3=1111 1111 22222 2222
- 显然答案应该是
max(s3, s4)
。
- 摘自题解:https://www.acwing.com/solution/content/50564/ 人家写的更加清楚~疯狂学习!!
- 输入1,s1直接加1
- 输入2,s2的长度等于(s1的长度 + 连续2)的长度,最坏情况下连续2仅有一个,那输入2之后s2只能更新成s1+1的长度,如果不是最坏情况则直接s2+1,写成式子就是s2 =
max(s1+1,s2+1)- 输入1,s3的长度等于(s2的长度+连续1)的长度,最坏情况下连续1仅有一个,那输入1之后s3只能更新为s2+1的长度,如果不是最坏情况则直接s3+1,写成式子就是s3
= max(s2+1,s3+1)- s4…同理,最坏s3+1,正常s4+1
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6+5;
int n;
int main() {
scanf("%d", &n);
int s1 = 0, s2 = 0, s3 = 0, s4 = 0;
for (int i = 0; i < n; i ++ ) {
int x;
scanf("%d", &x);
if (x == 1) {
s1 = s1 + 1;
s3 = max(s2 + 1, s3 + 1);
} else {
s2 = max(s1 + 1, s2 + 1);
s4 = max(s3 + 1, s4 + 1);
}
}
printf("%d\n", max(s3, s4));
return 0;
}