删除序列
题目:
给定一个长度为 nn 的正整数序列 a1,a2,…,ana1,a2,…,an。
你可以进行任意次删除操作。
每次删除操作分为两步:
- 选择序列中的一个元素(不妨设其元素值为 xx),并将这一个元素删除,这可以给你加 xx 分。
- 将所有的元素值为 x−1x−1 和 x+1x+1 的元素(如果有的话)从序列中删除,这不会给你带来任何分数。
请计算,通过删除操作,你可以获得的最大得分。
输入格式
第一行包含整数 nn。
第二行包含 nn 个正整数 a1,a2,…,ana1,a2,…,an。
输出格式
一个整数,表示可以获得的最大得分。
数据范围
前 66 个测试点满足 1≤n≤101≤n≤10。
所有测试点满足 1≤n≤1051≤n≤105,1≤ai≤1051≤ai≤105。
方法:
1.首先排序,按照贪心原则,如果选 a i a~i a i,那么,与之数值相等的必须得选,所以可以利用pair类型的b数组存储,第一维是数值,第二维度是个数。
2.数据范围是1e5,考虑dp,从前往后扫一遍,由于考虑到某个数值的时候,会被其前面的状态影响,所以用状态机dp,f【i】【0】表示不选第i个数的最大价值,f【i】【1】表示选第i个数的最大价值,答案是
max(f【cnt】【0】和f【cnt】【1】)(cnt表示b数组大小)
3.转移方程:见代码
代码:
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<set>
#include<vector>
#include<deque>
#include<cmath>
#include<bitset>
#include<unordered_map>
#include<stack>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
int n;
int a[N];
ll f[N][2];//表示删除第i个元素么?
pair<ll,ll> b[N];
int cnt;
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)cin >> a[i];
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; i++) {
if (b[cnt].first != a[i])b[++cnt] = { a[i],1 };
else b[cnt].second++;
}
for (int i = 1; i <= cnt; i++) {
f[i][0] = max(f[i - 1][1], f[i - 1][0]);
if (b[i].first - 1 == b[i - 1].first) {
//前一个必须不选
f[i][1] = f[i - 1][0] + b[i].second * b[i].first;
}
else {
f[i][1]=max(f[i-1][0],f[i-1][1])+ b[i].second * b[i].first;
}
}
cout << max(f[cnt][0], f[cnt][1]);
return 0;
}