简单的桶排

给定一个由 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值