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 a1, a2, ..., an.
Little Tommy is among them. He would like to choose an interval [l, r] (1 ≤ l ≤ r ≤ n), then reverse al, al + 1, ..., ar 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 p1, p2, ..., pk, such that p1 < p2 < ... < pk and ap1 ≤ ap2 ≤ ... ≤ apk. 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 a1, a2, ..., an (1 ≤ ai ≤ 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.
4
1 2 1 2
4
10
1 1 2 2 2 1 1 2 2 1
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.
思路一:(比赛时的想法)先对于原始序列,预处理出每个位置(含本身)之前有多少个1,之后有多少个2,然后再扫一遍统计出没翻转时的最大答案。之后考虑翻转后的情况,对于每个合法子序列,把第一次出现2的位置定义为分隔点,那么如果分隔点在翻转区间外,对结果是没有影响的,要考虑的只是分隔点在翻转区间内部的情况。暴力枚举区间并统计是O(n^3)的,考虑一下优化。枚举区间时,固定左端点,右端点向右移动,每次新出现的元素如果是1,那么统计值直接加1,如果是2,要想对答案有影响,那么这段翻转区间的贡献就是2的个数,这个东西可以用个常量维护出来。时间复杂度O(n*n),空间复杂度O(n)。
废话:从看题到过题用了20分钟,当时感觉自己分析的很精髓,此时大概40到50人过了这题,rank17,内心小得意。刚才才知道可以O(n)做,看来分析地并不精髓,果然还是菜...
#include <iostream> #include <fstream> #include <sstream> #include <cstdlib> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <queue> #include <stack> #include <vector> #include <set> #include <map> #include <list> #include <iomanip> #include <cctype> #include <cassert> #include <bitset> #include <ctime> using namespace std; #define pau system("pause") #define ll long long #define pii pair<int, int> #define pb push_back #define mp make_pair #define clr(a, x) memset(a, x, sizeof(a)) const double pi = acos(-1.0); const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; const double EPS = 1e-9; int n, a[2015]; int pre1[2015], suf2[2015], ans; int main() { scanf("%d", &n); for (int i = 1; i <= n; ++i) scanf("%d", &a[i]); for (int i = 1; i <= n; ++i) { pre1[i] = (1 == a[i] ? pre1[i - 1] + 1 : pre1[i - 1]); } for (int i = n; i; --i) { suf2[i] = (2 == a[i] ? suf2[i + 1] + 1 : suf2[i + 1]); } for (int i = 1; i <= n; ++i) { if (2 == a[i]) { ans = max(ans, pre1[i] + suf2[i]); } } for (int l = 1; l <= n; ++l) { int t1 = pre1[l - 1], ma = 0, cnt_2 = 0; for (int r = l; r <= n; ++r) { int t2 = suf2[r + 1]; if (1 == a[r]) { ++ma; } else { ++cnt_2; ma = max(ma, cnt_2); } ans = max(ans, t1 + t2 + ma); } } printf("%d ", ans); return 0; }
思路二:翻转后的合法子序列翻转前一定是 一坨1 + 一坨2 + 一坨1 + 一坨2形式,坨可以为空,于是可以用4个变量分别维护前1坨,前2坨,前3坨,前4坨的最大值,更新时每个变量也只用上一轮最多两个变量更新,比如当前元素为2,那么前两坨的最大值ma2 = max(ma1, ma2) + 1,ma4 = max(ma3, ma4) + 1。因为将2接到ma1或ma2后的序列都是合法的ma2形式。代码十分简短。时间复杂度O(n),空间复杂度O(1)。
#include <iostream> #include <fstream> #include <sstream> #include <cstdlib> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <queue> #include <stack> #include <vector> #include <set> #include <map> #include <list> #include <iomanip> #include <cctype> #include <cassert> #include <bitset> #include <ctime> using namespace std; #define pau system("pause") #define ll long long #define pii pair<int, int> #define pb push_back #define mp make_pair #define clr(a, x) memset(a, x, sizeof(a)) const double pi = acos(-1.0); const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; const double EPS = 1e-9; int ma1, ma2, ma3, ma4, x, n; int main() { scanf("%d", &n); for (int i = 1; i <= n; ++i) { scanf("%d", &x); if (1 == x) { ++ma1; ma3 = max(ma3, ma2) + 1; } else { ma2 = max(ma1, ma2) + 1; ma4 = max(ma4, ma3) + 1; } } printf("%d ", max(ma3, ma4)); return 0; }