链接:
https://codeforces.com/problemset/problem/455/A
题意
给你一个长度为n的数组,你可以进行多次操作,每次操作选定一个位置,该位置的数ak以及数值上等于ak+1或者ak-1的元素都将删除,然后得分+=ak,求最大得分。
1 ≤ n ≤ 105
1 ≤ ai ≤ 105
Example
input
2
1 2
output
2
input
3
1 2 3
output
4
input
9
1 2 1 3 2 2 2 2 3
output
10
解析
这题原本想用暴力直接找出最大得分,但是数据是1e5,会超时,所以换一种思路:选择一个数字它影响的是它的+1和-1,这个数字可以使用它出现的次数,就比如数字5出现了3次,虽然数字4和数字6在选择数字5的时候被删除,但是数字5自己本身只是被删除了1次,所以可以删除3次数字5,得分就是5 * 3 = 15。
所以可以从小遍历到最大的那个数字,将得分累加到最大的那个数字上,不过每次都需要判断,要么选择这个数字的前一个数字,这个数字得分不计(因为被删除了),要么选择这个数字再前面一个数字,然后再加上这个数字的得分,比较选择二者中最大的那个值。
注意:一定要记得开long long!!!因为最多有1e5个,每个数最大是1e5,所以得分是有可能是1e5*1e5的,会超int范围,因为这个WA一组案例好多遍(—_—)
#include <iostream>
#include <cmath>
#include <algorithm>
#include <string>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
ll num[N], n, max_num, ans[N];
int main()
{
cin >> n;
while (n--)
{
ll x;
cin >> x;
num[x]++;//记录每个数字出现的次数,得分就是数字*它的出现次数
max_num = max(max_num, x);
}
//接下来从小到大遍历过去将得分逐步累加至最大数字
memcpy(ans, num, sizeof num);
for (int i = 2; i <= max_num; i++)
{
ans[i] = max(ans[i - 1], ans[i - 2] + num[i] * i);//计算这个数的得分时,要考虑前面一个选择的数字是不是i - 1
//如果是i - 1,那这个i就被删除了,那就再前一个的得分加上自己的得分
//如果不是i - 1,就是再前一个数的得分
}
cout << ans[max_num];
return 0;
}