D. Jellyfish and Mex Codeforces Round 901 (Div. 2)

Problem - D - Codeforces

题目大意:有一个n个数的数组a,数m初始为0,每次操作可以删除任意一个数,然后m加上那个数,求n次操作和m的最小值

1<=n<=5000;0<=ai<=1e9

思路:可以发现,如果我们要删除某个数,那么一定要把所有和这个数相等的数全部删去,这样才能使MEX变小,同时,所有大于MEX的数删去的花费都是0,所以我们每次操作的数的大小都是递减的,且只会操作MEX到0。

那么我们令dpi等于MEX等于i时的最小花费,我们从MEX到0枚举i,同时枚举该删哪个数,也就是从0到i-1遍历,当前最小花费就是不删这个数dpj,或者删这个数也就是dpi+当前MEX*(这个数数量-1)再加这个数,转移方程为dpj=min(dpj,dpi+i*(cntj-1)+j)

cpp 复制代码
//#include<__msvc_all_public_headers.hpp>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e3 + 5;
ll n;
ll a[N];
ll cost[N];
ll cnt[N];
void init()
{
	for (int i = 0; i <= n; i++)
	{
		cost[i] = 1e18;
		cnt[i] = 0;
	}
}
ll gcd(ll a, ll b)
{
	return b ? gcd(b, a % b) : a;
}
ll lowbit(ll x)
{
	return x & (-x);
}
void solve()
{
	ll m;
	cin >> n;
	init();
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		if (a[i] <= n)
		{//MEX最大为n,大于n的都可以随便删
			cnt[a[i]]++;
		}
	}
	int mex = 0;
	while (cnt[mex])
	{//找当前的MEX
		mex++;
	}
	cost[mex] = 0;
	for (ll i = mex; i >= 0; i--)
	{
		for (ll j = 0; j < i; j++)
		{
			cost[j] = min(cost[j], cost[i] + i * (cnt[j] - 1) + j);
		}
	}
	cout << cost[0] << endl;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t;
	cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}
相关推荐
wabs6666 小时前
关于贪心算法的思考
算法·贪心算法
社交怪人7 小时前
【判断大小】信息学奥赛一本通C语言解法(题号1043)
算法
Snasph7 小时前
GNU Make 用户手册(中文版)
服务器·算法·gnu
江澎涌7 小时前
拆解与 AI 的一次对话
人工智能·算法·程序员
sheeta19988 小时前
LeetCode 每日一题笔记 日期:2026.06.02 题目:3635. 最早完成陆地和水上游乐设施的时间 II
笔记·算法·leetcode
Lsk_Smion8 小时前
力扣实训 _ [102].层序遍历--前序--后续_递归与非递归的实现
数据结构·算法·leetcode
小欣加油9 小时前
leetcode3751 范围内总波动值I
java·数据结构·c++·算法·leetcode
代码中介商10 小时前
C++左值与右值:核心判断法则详解
开发语言·c++
玖玥拾10 小时前
C/C++ 基础笔记(七)
c语言·c++
Halo_tjn10 小时前
反射与设计模式1
java·开发语言·算法