acwing第86场周赛

删除序列

题目:

给定一个长度为 nn 的正整数序列 a1,a2,…,ana1,a2,…,an。

你可以进行任意次删除操作。

每次删除操作分为两步:

  1. 选择序列中的一个元素(不妨设其元素值为 xx),并将这一个元素删除,这可以给你加 xx 分。
  2. 所有元素值为 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值