给定一个由 n 个整数组成的数组 a 。玩家可以执行以下操作几次。 在单次操作中,他可以选择数组中的一个元素 ( 让我们称它为 ak ) 并删除它,所有等于 ak + 1 和 ak - 1 的元素都会被一并删除,这样的一次操作可以得到 ak 分。
得到尽可能多的分数。
输入
第 1 行包含 1 个整数 n (1 ≤ n ≤ 105) ——代表数组元素个数。
第 2 行包含 n 个整数: a1, a2, …, an (1 ≤ ai ≤ 105).
输出
输出 1 个整数代表能获得的最大分数。
样例
输入
2
1 2
输出
2
输入
3
1 2 3
输出
4
输入
9
1 2 1 3 2 2 2 2 3
输出
10
提示
在第 3 个样例中,第一次操作我们需要选择任意一个等于 2 的元素。在这一次操作之后,数组变成 [2,2,2,2] 。然后我们再做4次操作,每一次操作都选择一个等于2的元素。这样小图最多能得 10 分。
一开始我的思路是桶排统计每个数出现的次数,然后分成两大种情况:第一种是每个数字都出现了一次,剩下的情况就归到第二类,然后在第二类中再分出现最多的数p的奇偶两种情况,循环相加最高项(p*a[p])和与最高项差2的其他项(p±2)*a[p±2],不过提交后wa,显然我想的并不是正确思路,看了题解后得用到了dp,对于dp我一点都不会,只是知道一点点,想这道题的时候压根没联系到dp,这个假期希望能学会,
计算结果于顺序无关所以先桶排,f[i]表示到i的时候最大得分,DP分两种情况 不取 f[i-1]
取i a[i]*i+f[i-2]
n=read();
for(int i=1;i<=n;i++) a[read()]++;
for(int i=1;i<=100000;i++) f[i]=max(f[i-2]+a[i]*i,f[i-1]);
cout << f[100000] << endl;
大神的题解
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
int n, arr, c[maxn];
int main () {
cin >> n;
memset(c, 0, sizeof(c));
for (int i = 0; i < n; i++) {
cin >> arr;
c[arr]++;
}
ll p = 0, q = 0;
for (int i = 1; i < maxn; i++) {
ll tmp = q + 1LL * i * c[i];
q = max(p, q);
p = tmp;
}
cout << max(p, q) << endl;
return 0;
}