1. 程式人生 > >Codeforces-462C. A Twisty Movement

Codeforces-462C. A Twisty Movement

ems .com pos 答案 type define 得到 body std

傳送門

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; }

Codeforces-462C. A Twisty Movement