zoukankan      html  css  js  c++  java
  • CF1272D. Remove One Element 题解 动态规划

    题目链接:http://codeforces.com/contest/1272/problem/D

    题目大意:
    给你一个长度为 (n) 的数组,你最多删除一个元素(也可以不删),求此条件限制下的最长上升子串长度。

    解题思路:
    本题涉及算法:动态规划。

    首先这里有一个条件“你最多可以删除一个元素”,这个条件会造成我们很多的困扰,所以为了避免困扰,我们先尝试在没有这个条件的情况下解决问题。

    在我们没有删除元素的权限下,数组 (a) 中的 (n) 个元素是固定的,所以此时我们可以定义状态 (f[i]) 表示以 (a[i]) 结尾并且包含 (a[i]) 的最长上升子串的长度,那么我们可以发现(设数组坐标从 (1) 开始):

    (f[1]=1)
    (i gt 1) 时,

    • 如果 (a[i-1] < a[i]) ,则 (f[i] = f[i-1]+1)
    • 否则,(f[i]=1)

    代码实现:

    f[1] = 1;
    for (int i = 2; i <= n; i ++) {
        if (a[i-1] < a[i]) f[i] = f[i-1]+1;
        else f[i] = 1;
    }
    

    然后我们需要求的最长上升子串长度就是所有 (f[i]) 中最大的那个。
    稍等一下,我们暂时还是不加上“你最多可以删除一个元素”这个条件。
    在加上这个条件之前,我们再定义一个状态 (g[i]) 表示以 (a[i]) 开头并且包含 (a[i]) 的最长上升子串的长度,那么,我们可以得到状态转移方程:

    (g[n] = 1)
    (i < n) 时,

    • 如果 (a[i] < a[i+1]),则 (g[i] = g[i+1]+1)
    • 否则,(g[i] = 1)

    代码实现(注意 (g[i]) 需要从 (n)(1) 反着推):

    g[n] = 1;
    for (int i = n-1; i >= 1; i --) {
        if (a[i] < a[i+1]) g[i] = g[i+1]+1;
        else g[i] = 1;
    }
    

    那么我们求完 (f[i])(g[i]) 之后呢,我们再来加回“你最多可以删除一个元素”这个条件。

    首先,如果我们不删除元素,那么答案就是所有 (f[i]) 中的最大值,我们开一个变量 (ans = max(f[i]))

    其次,如果我们删除元素的坐标是 (i) ,我们假设删除元素后的最长上升子串对应为 (a[l])(a[r])
    那么如果 (i) 不满足 (l < i < r) 的条件,那么我删或者不删 (a[i]) 对我答案丝毫不影响(仍然是 (ans = max(f[i])))。

    那么什么时候会对答案有影响呢?
    就是当 (1 < i < n)(a[i-1] < a[i+1]) 的时候,我删除 (a[i]) 能够使得 (f[i-1] + g[i+1] > ans) 的时候,说明删除元素 (a[i]) 达到了增长最长上升子串的效果,此时我们更新 (ans = f[i-1] + g[i+1])

    综上所述,答案应该是

    • (max(f[i])) (其中 ((1 le i le n))
    • (max(f[i-1]+g[i+1])) (其中 (1 lt i lt n)(a[i-1] < a[i+1])

    的较大值。

    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 200020;
    int n, a[maxn], f[maxn], g[maxn], ans;
    int main() {
        cin >> n;
        for (int i = 1; i <= n; i ++) cin >> a[i];
        f[1] = 1;
        for (int i = 2; i <= n; i ++) {
            if (a[i-1] < a[i]) f[i] = f[i-1]+1;
            else f[i] = 1;
        }
        g[n] = 1;
        for (int i = n-1; i >= 1; i --) {
            if (a[i] < a[i+1]) g[i] = g[i+1]+1;
            else g[i] = 1;
        }
        for (int i = 1; i <= n; i ++) ans = max(ans, f[i]);
        for (int i = 2; i < n; i ++) if (a[i-1] < a[i+1]) ans = max(ans, f[i-1] + g[i+1]);
        cout << ans << endl;
        return 0;
    }
    
  • 相关阅读:
    MariaDB:SSL配置
    JDBC连接MariaDB:数据传输加密
    海康JAVA SDK库动态路径加载
    druid:java代码创建连接池
    webservice:com.sun.xml.internal.ws.server.ServerRtException: [failed to localize]
    RabbitMQ:MSVCR120.dll ,c000001d 错误
    mariadb:分区自动创建与删除
    前-后 分离 01
    03 注解开发
    02
  • 原文地址:https://www.cnblogs.com/quanjun/p/12041388.html
Copyright © 2011-2022 走看看