• 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);

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


    代码:

    #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;
    }
  • 相关阅读:
    表单
    超链接
    图像
    表格
    排列清单控制标
    HTML基本结构
    如何快速查看网页源代码
    TOR的使用
    google搜索新姿势
    [NOIP2017]列队
  • 原文地址:https://www.cnblogs.com/HotPants/p/12075315.html
Copyright © 2020-2023  润新知