CodeForces - 934C Twisty Movement

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37129433/article/details/81843109

Twisty Movement
题 意:给你一个长度为n的数组只包含0,1问然让你翻转一段区间后的最长不递减子序列。
数据范围:
1<=n<=2e3
输入样例:

4
1 2 1 2

输出范围:

4

思 路:这题数据范围可以n^2枚举开始和结束位置。那么最长不下降子序列就等于pre[i-1]1个数的前缀和 + dp[i][j] 区间i,j的最长不递增子序列 + last[j+1] (2个数的后缀)。
那么如果维护区间最长不递增子序列呢?因为它只有1和2,那么可以这样转移状态,
dp[i][j][0] 表示区间i,j以2为结尾的最长不上升子序列。dp[i][j][1]表示区间i,j,以1为结尾的最长不上升子序列。那么状态转移方程dp[i][j][0] = dp[i][j-1][0] + a[j] == 2,
dp[i][j][1] = dp[i][j-1][1] + (a[j] == 1) 如果a[j] == 1那么dp[i][j][1] = max(dp[i][j][1],dp[i][j-1][2]+1)
收 获:思路要开阔,n^2枚举区间,下个就应该想到的就是反转区间,也就是要求最长不上升子序列。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e3+5;
int dp[maxn][maxn][2];
int pre[maxn],last[maxn];
//dp[i][j][0] 以2为结尾的最长下降子序列
//dp[i][j][1] 以1为结尾的最长下降子序列
//状态转移方程dp[i][j][0] = dp[i][j-1][0] + a[j] == 2?
//            dp[i][j][1] = max(dp[i][j-1][0] , dp[i][j-1][1]) + a[j] == 1?
int a[maxn];
int n;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)pre[i] = pre[i-1]+(a[i]==1);
    for(int i=n;i>=1;i--)last[i] = last[i+1]+(a[i]==2);
//    printf("#%d\n",last[4]);
    int ans = 0;
    for(int i=1;i<=n;i++){
        for(int j=i;j<=n;j++){
            dp[i][j][0] = dp[i][j-1][0] + (a[j] == 2);
            dp[i][j][1] = dp[i][j-1][1] + (a[j] == 1);
            if(a[j] == 1)dp[i][j][1] = max(dp[i][j][1],dp[i][j][0]+1);
            ans = max(ans,pre[i-1] + dp[i][j][0] + last[j+1]);
            ans = max(ans,pre[i-1] + dp[i][j][1] + last[j+1]);
        }
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37129433/article/details/81843109