Codeforces 1272D

题意:给定一个长度为n的数组a,你至多可以删去其中的一个元素,找出最长的连续(严格)上升子序列的长度。

    分析:读完题之后可以发现这道题和模板:连续上升子序列很相像,首先可以确定方向是dp:状态是当前的位置,目标是连续(严格)上升子序列的长度,即dp[i]表示以a[i]为结尾的最长的连续(严格)上升子序列的长度。但是,这道题不同于模板的地方就在于题目中给定了一个条件:至多可以删去其中的一个元素,乍一看似乎很难再做状态转移,但是不妨将删去这件事本身也引入状态转移中来。

    不难想到“已经删去一个元素”的状态一定是由“没有删去元素”的状态转移过来的,我们可以使用dp第二维来表示是否已经删去了一个元素,即dp[i][0]表示在没有删去一个元素的前提下以a[i]为结尾的最长(严格)连续上升子序列的最长长度,而dp[i][1]则是以已经山区了一个元素为前提下的最长长度。想到这里,便可以开始推状态转移方程:


首先第一步,先不考虑删去元素的状态转移,dp[i][0]这个状态一定是由dp[i-1][0]转移而来的,即如果a[i] > a[i-1],则dp[i][0] = dp[i-1][0]+1;如果第二维=1,同样也不难想到,在这种情况下也是直接由dp[i-1][1]+1转移而来即可。

当a[i] > a[i-1]时,dp[i][0 or 1] = max(dp[i][0],dp[i-1][0 or 1]+1);

第二步:考虑删去元素的情况。倘若我们现在想要得到dp[i],考虑删去a[i-1],这样删去的时候,在从左到右的递推过程中就可以把所有的情况都覆盖到,而不会漏解或重复运算,并且删去a[i-1]使得dp[i]变化的条件是a[i] > a[i-2],也就是当前这一位数比它之前的之前一位数还要大时,删去它之前的数,可能会导致它的最长长度有所变化,其中就可能导致最大长度变大,因此,当a[i] > a[i-2]时,有:dp[i][1] 由 dp[i-2][0] + 1 转移而来。

当a[i] > a[i-2]时,dp[i][1] = max(dp[i][1],dp[i-2][0]+1);

那么综合前两步,不难得出状态转移方程,递推完方程之后,每一步更新结果即可。


代码:

扫描二维码关注公众号,回复: 8258522 查看本文章
#include <iostream>
#include <algorithm>
 
using namespace std;
const int N = 200005;
int dp[N][2],a[N];
int main()
{
    int n;cin >> n;
    for(int i = 1;i <= n;++i)
        cin >> a[i];
    dp[1][0] = 1;
    int res = -1;
    for(int i = 2;i <= n;++i)
    {
        dp[i][0] = 1;dp[i][1] = 1;
        if(a[i] > a[i-1])
        {
            dp[i][0] = max(dp[i-1][0] + 1,dp[i][0]);
            dp[i][1] = max(dp[i-1][1] + 1,dp[i][1]);
        }
        if(a[i] > a[i-2])
            dp[i][1] = max(dp[i-2][0] + 1,dp[i][1]);
        res = max(res,max(dp[i][0],dp[i][1]));
    }
    cout << res;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/HotPants/p/12075315.html
今日推荐