N个数,为1或2.由一次操作,对一段区间进行反转,然后求最长不下降子序列长度
emmm想的是如果反转区间可以使答案较原本序列更大,那么区间内对答案的贡献必然是一个1与2组成的序列。总共反转的区间有n^2个,那么如果我们对于每个反转序列,能够O(1)得求出贡献即可得到答案,因为区间前1的数目与区间后2的数目只需维护前缀和即可O(1)求得。
我们用dp[j][i]代表从区间[j, i]能得到的同时包含1 2的不降序列的长度.
A[i]==1时,dp[j][i] = dp[j + 1][i];
A[i]==2, dp[j][i] = 1 + max([j+1,i]1的数目,dp[j+1][i]);
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define INF 0x3f3f3f3f using namespace std; typedef long long LL; const int maxn = 2e3 + 10; int N; int A[maxn]; int cnt[maxn][2]; int dp[maxn][maxn]; int ans[maxn]; int main() { scanf("%d", &N); for (int i = 1; i <= N; i++) scanf("%d", &A[i]); memset(cnt, 0, sizeof(cnt)); for (int i = 1; i <= N; i++) { if (A[i] == 1) { cnt[i][0] = cnt[i - 1][0] + 1; cnt[i][1] = cnt[i - 1][1]; } else { cnt[i][0] = cnt[i - 1][0]; cnt[i][1] = cnt[i - 1][1] + 1; } } for (int i = 1; i <= N; i++) { ans[i] = 1; for (int j = 1; j < i; j++) { if (A[j] <= A[i]) { ans[i] = max(ans[i], ans[j] + 1); } } } memset(dp, 0, sizeof(dp)); int res = ans[N]; for (int i = N; i >= 1; i--) { for (int j = i - 1; j >= 1; j--) { if (A[j] == 1) { dp[j][i] = dp[j + 1][i]; } else { int t = cnt[i][0] - cnt[j][0]; dp[j][i] = max(t, dp[j + 1][i]) + 1; } } } for (int i = 1; i <= N; i++) { for (int j = i + 1; j <= N; j++) { int t1 = cnt[i - 1][0]; int t2 = cnt[N][1] - cnt[j][1]; int tt = t1 + t2 + dp[i][j]; if (tt > res) { res = tt; } } } printf("%d\n", res); return 0; }