单调序列 解题报告

单调序列

( t{GISPZJZ}) 有一个长度为 (n) 的序列 (a_1,a_2,dots,a_n)。 序列的所有元素都是 (1) 或者 (2)
我们称一序列是该序列的不下降子序列 (p_1,p_2,dots,p_k), 满足 (1le p_1<p_2<p_3<dots <p_kle n), 且(a_{p_1}le a_{p_2}le dots le a_{p_n})
现在 ( t{GISPZJZ}) 可以选择序列中的一段区间([L,R]), 然后将整段反转, 例如挑选区间([2,4]),可以将序列((a_1,a_2,a_3,a_4,a_5))变换为((a_1,a_4,a_3,a_2,a_5))。 在此基础上, ( t{GISPZJZ}) 希望在反转后, 序列的最长不下降子序列最长。 当然, ( t{GISPZJZ}) 也可以选择不反转任何区间。 现在要求出最优情况下, 序列的最长不下降子序列的长度。

输入:

第一行一个正整数 (n)
第二行 (n) 个数, 分别为 (a_1,a_2,dots,a_n), 满足 (1le a_ile 2)

输出:

一行一个正整数 (x), 表示答案。

数据范围:

对于(10\%)的数据, (1le nle 10)
对于(40\%)的数据, (1le nle 200)
对于(70\%)的数据, (1le n le 2000)
对于(100\%)的数据, (1le nle 100000)


思路还是很巧妙的。

最开始想把一串的缩在一起做,发现讨论起来非常麻烦。

观察了一下发现翻转后不就是把(000111)什么的变成了可以选(000111000111)这样类似的了吗?

于是直接划分一下状态( t{DP})即可,是一个非常好的思路啊。


Code:

#include <cstdio>
const int N=1e5+10;
int a[N],dp[N][4],n,ans;
int max(int x,int y){return x>y?x:y;}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",a+i),--a[i];
    for(int i=1;i<=n;i++)
    {
        dp[i][0]=dp[i-1][0]+(a[i]==0);
        dp[i][1]=max(dp[i-1][0],dp[i-1][1])+(a[i]==1);
        dp[i][2]=max(dp[i-1][1],dp[i-1][2])+(a[i]==0);
        dp[i][3]=max(dp[i-1][2],dp[i-1][3])+(a[i]==1);
        ans=max(max(dp[i][0],dp[i][1]),max(dp[i][2],dp[i][3]));
    }
    printf("%d
",ans);
    return 0;
}

2017.11.2

原文地址:https://www.cnblogs.com/butterflydew/p/9896022.html