CF455ABoredom

题目大意:

给你一个由 \(n\) 个整数构成的序列 \(a\),玩家可以进行几个步骤,每一步他可以选择序列中的一个元素(我们把它的值定义为 \(a_k\))并删除它,此时值等于 \(a_{k + 1}\)\(a_{k - 1}\) 的所有元素也都必须从序列中被删除。这次操作会给玩家加 \(a_k\) 分。

  在样例这一数据中,我们先删除一个 \(2\) ,以此删去所有的 \(1,3\),得到一个全为 \(2\) 的序列,接下来,我们无论如何删除,都不会将 \(2\) 删去。由此我不禁产生了一个想法:是不是得到一个全部数字相等的序列,再挨个删除,就可以使结果最大化呢?
  显然,这样的思考不够全面。于是想到了动态规划。因为 \(1≤ {a_i} ≤ {10^5}\),不妨将数字定为状态,\(dp[i]\) 表示将前 \(i\) 种数删除完后所能得到的最大分数。因为每删除一个 \(i\)\(i - 1\)\(i + 1\) 这两种数都要被删除,而若想保留 \(i\) ,就只能删除 \(i - 2\),于是我们不难得到如下的状态转移方程:

\[dp[i] = \max(dp[i - 1],dp[i - 2] + a[i] * i) \]

(其中 \(a[i]\) 表示在输入的数据中 \(i\) 出现的次数)

AC代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
long long  a[N];//记录i出现的次数 
long long dp[N];
int main(){
    int n;
	cin >> n;
    for(int i = 1;i <= n;i++){
        int x;
		cin >> x;
        a[x]++;
    }
    dp[1] = a[1];
    for(int i = 2;i <= 100002;i++){
        dp[i] = max(dp[i-1],dp[i-2]+i*a[i]);
    }
    cout<< dp[100002]<<endl;
    return 0;
}
posted @ 2022-07-17 19:09  腾云今天首飞了吗  阅读(22)  评论(0编辑  收藏  举报