Codeforces Round #462 (Div. 2):C. A Twisty Movement(预处理)

C. A Twisty Movement
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

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.

Input

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).

Output

Print a single integer, which means the maximum possible length of the longest non-decreasing subsequence of the new sequence.

Examples
input
4
1 2 1 2
output
4
input
10
1 1 2 2 2 1 1 2 2 1
output
9
Note

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.

思路:因为a数列中只有1和2,那么可以预处理出[1,i]中以1或2结尾的最长上升子序列的长度,和[i,n]中以1或2开头的最长上升子序列的长度。还要预处理出翻转区间的上述长度。然后枚举翻转区间,更新答案。具体看代码。
#include<bits/stdc++.h>
using namespace std;
const int MAX=3e3;
const int MOD=1e9+7;
typedef __int64 ll;
int a[MAX];
int suf[MAX][3],pre[MAX][3];//pre suf分别为以1或2结尾 开头 的最长子序列的长度
int num1[MAX][MAX];//记录区间[i,j]的1的个数
int num2[MAX][MAX];//记录区间[i,j]的2的个数
int d[MAX][MAX][2];//区间[i,j] 以1或2结尾的最长子序列的长度
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    memset(pre,0,sizeof pre);
    memset(suf,0,sizeof suf);
    for(int i=1;i<=n;i++)//以1或2结尾的最长子序列的长度
    {
        pre[i][1]=pre[i-1][1];
        pre[i][2]=max(pre[i-1][1],pre[i-1][2]);
        if(a[i]==1)pre[i][1]++;
        else pre[i][2]++;
    }
    for(int i=n;i>=1;i--)//以1或2开头的最长子序列的长度
    {
        suf[i][2]=suf[i+1][2];
        suf[i][1]=max(suf[i+1][1],suf[i+1][2]);
        if(a[i]==1)suf[i][1]++;
        else suf[i][2]++;
    }
    memset(num1,0,sizeof num1);
    memset(num2,0,sizeof num2);
    for(int i=1;i<=n;i++)//区间[i,j]以1或2结尾的最长子序列的长度
    {
        for(int j=i;j<=n;j++)
        {
            num1[i][j]=num1[i][j-1]+(a[j]==1);
            num2[i][j]=num2[i][j-1]+(a[j]==2);
            d[i][j][2]=max(d[i][j-1][1],d[i][j-1][2]);
            d[i][j][1]=d[i][j-1][1];
            if(a[j]==1)d[i][j][1]++;
            else d[i][j][2]++;
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=i;j<=n;j++)//枚举翻转的区间并更新答案
        {
            ans=max(ans,pre[i-1][1]+num1[i][j]+suf[j+1][1]);
            ans=max(ans,pre[i-1][1]+num1[i][j]+suf[j+1][2]);
            ans=max(ans,pre[i-1][1]+num2[i][j]+suf[j+1][2]);
            ans=max(ans,pre[i-1][2]+num2[i][j]+suf[j+1][2]);
            ans=max(ans,pre[i-1][1]+j-i+1-d[i][j][2]+suf[j+1][2]);
            ans=max(ans,pre[i-1][1]+j-i+1-d[i][j][1]+suf[j+1][1]);
        }
    }
    cout<<ans<<endl;
    return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值