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;
}
posted @ 2019-12-14 22:48  quanjun  阅读(506)  评论(0编辑  收藏  举报