A Twisty Movement
洛谷連結:https://www.luogu.com.cn/problem/CF933A
codeforce連結:https://codeforces.com/problemset/problem/933/A
題面翻譯
給定一個序列 A,你可以翻轉其中的一個區間內的數,求翻轉後的序列的最長不下降子序列的長度。(\(|A|\le 2000,1\le a_i \le 2\) )
感謝@touristWang 提供的翻譯
題目描述
A dragon symbolizes wisdom, power and wealth. On Lunar New Year's Day, people model a dragon with bamboo strips and clothes, raise them with rods, and hold the rods high and low to resemble a flying dragon.
A performer holding the rod low is represented by a $ 1 $ , while one holding it high is represented by a $ 2 $ . Thus, the line of performers can be represented by a sequence $ a_{1},a_{2},...,a_{n} $ .
Little Tommy is among them. He would like to choose an interval $ [l,r] $ ( $ 1<=l<=r<=n $ ), then reverse $ a_{l},a_{l+1},...,a_{r} $ so that the length of the longest non-decreasing subsequence of the new sequence is maximum.
A non-decreasing subsequence is a sequence of indices $ p_{1},p_{2},...,p_{k} $ , such that $ p_{1}<p_{2}<...<p_{k} $ and $ a_{p1}<=a_{p2}<=...<=a_{pk} $ . The length of the subsequence is $ k $ .
輸入格式
The first line contains an integer $ n $ $ (1<=n<=2000) $ , denoting the length of the original sequence.
The second line contains $ n $ space-separated integers, describing the original sequence $ a_{1},a_{2},...,a_{n} $ $ (1<=a_{i}<=2,i=1,2,...,n) $ .
輸出格式
Print a single integer, which means the maximum possible length of the longest non-decreasing subsequence of the new sequence.
樣例 #1
樣例輸入 #1
4
1 2 1 2
樣例輸出 #1
4
樣例 #2
樣例輸入 #2
10
1 1 2 2 2 1 1 2 2 1
樣例輸出 #2
9
提示
In the first example, after reversing $ [2,3] $ , the array will become $ [1,1,2,2] $ , where the length of the longest non-decreasing subsequence is $ 4 $ .
In the second example, after reversing $ [3,7] $ , the array will become $ [1,1,1,1,2,2,2,2,2,1] $ , where the length of the longest non-decreasing subsequence is $ 9 $ .
注意:解析扒的這位佬的 https://www.luogu.com.cn/article/fv3mhsdw
分析
考慮 DP
。
由於序列只有兩個數,那麼最終的非降子序列一定是 \(\{1, 1, \dots 1, 2, 2, \dots, 2\}\) 這樣的形式。可以這樣表示:\([1][2]\),表示分別由 \(1\) 和 \(2\) 組成的序列。其中這兩個部分可能為空。
如果翻轉後得到 \([1][2]\),那麼翻轉前的子序列應該是 \([1][2][1][2]\) 的形式,使得交換中間兩個子序列後變成非降子序列。同樣的,這些序列也可以為空。
因為最多交換一次,所以題目變成了找原序列的最長子序列,且形式為 \([1][2][1][2]\)。
一共有 \(4\) 部分,分別將其標號為 \(0 \sim 3\)。設狀態 \(f_{i, j}(j \in [0, 3])\) 表示序列前 \(i\) 個數中,選擇前 \(j\) 個序列的最長長度。接下來考慮轉移。
-
\(f_{i, 0}\),前 \(0\) 個部分:
如果第 \(i\) 個數為 \(1\),那麼可以把這個數和以前的拼起來。答案為 \(f_{i - 1, 0} + 1\)。
否則,如果第 \(i\) 個數為 \(2\),那麼這個數不可以作為第 \(0\) 部分。答案為 \(f_{i - 1, 0}\)。
因此 \(f_{i, 0} = \left\{\begin{matrix} f_{i - 1, 0} + 1 & (a_i = 1)\\ f_{i - 1, 0} & (a_i = 2)\end{matrix}\right.\)。
-
\(f_{i, 1}\),前 \(1\) 個部分。
如果第 \(1\) 個部分為空,那麼答案為 \(f_{i, 0}\)。以下都是不空的情況。
如果第 \(i\) 個數為 \(2\),那麼可以把這個數和以前的拼起來。答案為 \(f_{i - 1, 1} + 1\)。
否則,如果第 \(i\) 個數為 \(1\),那麼這個數不可以作為第 \(1\) 部分。答案為 \(f_{i - 1, 1}\)。
因此 \(f_{i, 1} = \left\{\begin{matrix} \max(f_{i, 0}, f_{i - 1, 1} + 1) & (a_i = 2)\\ \max(f_{i, 0}, f_{i - 1, 1}) & (a_i = 1)\end{matrix}\right.\)。
-
\(f_{i, 2}\),前 \(2\) 個部分。
如果第 \(2\) 個部分為空,那麼答案為 \(f_{i, 1}\)。以下都是不空的情況。
如果第 \(i\) 個數為 \(1\),那麼可以把這個數和以前的拼起來。答案為 \(f_{i - 1, 2} + 1\)。
否則,如果第 \(i\) 個數為 \(2\),那麼這個數不可以作為第 \(2\) 部分。答案為 \(f_{i - 1, 2}\)。
因此 \(f_{i, 2} = \left\{\begin{matrix} \max(f_{i, 1}, f_{i - 1, 2} + 1) & (a_i = 1)\\ \max(f_{i, 1}, f_{i - 1, 2}) & (a_i = 2)\end{matrix}\right.\)。
-
\(f_{i, 3}\),前 \(3\) 個部分。
如果第 \(3\) 個部分為空,那麼答案為 \(f_{i, 2}\)。以下都是不空的情況。
如果第 \(i\) 個數為 \(2\),那麼可以把這個數和以前的拼起來。答案為 \(f_{i - 1, 3} + 1\)。
否則,如果第 \(i\) 個數為 \(1\),那麼這個數不可以作為第 \(3\) 部分。答案為 \(f_{i - 1, 3}\)。
因此 \(f_{i, 3} = \left\{\begin{matrix} \max(f_{i, 2}, f_{i - 1, 3} + 1) & (a_i = 2)\\ \max(f_{i, 2}, f_{i - 1, 3}) & (a_i = 1)\end{matrix}\right.\)。
最後答案為 \(f_{n, 3}\)。
AC 程式碼:
#include <iostream>
using namespace std;
const int N = 2010;
int a[N];
int f[N][4];
int n;
int main()
{
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++)
{
f[i][0] = f[i - 1][0] + (a[i] == 1);
f[i][1] = max(f[i][0], f[i - 1][1] + (a[i] == 2));
f[i][2] = max(f[i][1], f[i - 1][2] + (a[i] == 1));
f[i][3] = max(f[i][2], f[i - 1][3] + (a[i] == 2));
}
cout << f[n][3];
return 0;
}