0%

3549-最长非递减子序列(翻转)

3549.最长非递减子序列

题目描述:

给定一个长度为 $ n $ 的序列,其中只包含数字 $ 1 $ 和 $ 2 $ 。选择一个区间 $ [l, r] $ 将元素翻转,使得到的序列的最长非递减子序列的长度最长。输出长度。

数据范围:
$ 1\le n \le 10^6 $

题解:

因为只有 $ 1 $ 和 $ 2 $ ,所以这就是突破口。翻转的话一定是翻转 $ 22222211111 $ 这种序列。翻转前的序列为 $ 111222221111 $ 或 $ 11122221111112222 $ 或 $ 22222211111122222 $ 。考虑使用 $ dp $ 转移。假设 $ a1 $ 表示类似 $ 111 $ 的全 $ 1 $ 序列,使用 $ a12 $ 表示类似 $ 111222 $ 的序列,使用 $ a121 $ 表示类似 $ 112211 $ 的序列,使用 $ a1212 $ 表示类似 $ 11222111122 $ 的序列

那么 $ a1 $ 可以转移到 $ a12 $ , $ a12 $ 转移到 $ a121 $ , $ a121 $ 转移到 $ a1212 $ ,答案就是 $ \max(a121, a1212) $

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using namespace std;
using namespace FAST_IO;
const ll mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const ll INF_LL = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-5;
const int maxn = 4e5 + 10;
const int maxm = 1e5 + 10;
int t, n, m, k;
int main()
{
// #define COMP_DATA
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
read(n);
int a1 = 0, a12 = 0, a121 = 0, a1212 = 0;
for (int i = 1, x; i <= n; i++)
{
read(x);
if (x == 1)
{
a1 += 1;
a121 = max(a121 + 1, a12 + 1);
}
else
{
a12 = max(a12 + 1, a1 + 1);
a1212 = max(a1212 + 1, a121 + 1);
}
}
printf("%d\n", max(a121, a1212));
return 0;
}