[NOI2019] 序列 题解

CF436E Cardboard Box的升级版。

直接上来搞六个堆的反悔贪心。

思路#

首先按照贪心的思路,将两个序列中最大 k 个直接选。

如果其中相同的小于 l ,我们考虑进行反悔贪心。

我们设当前序列相同的个数为 res

我们每一回合都要让 res+1

应该有四种情况:

  1. 选择一个之前选了 b 没选 a 的位置,将 a 选上,再丢掉一个只选了 a 的位置上的 a

  2. 选择一个之前选了 a 没选 b 的位置,将 b 选上,再丢掉一个只选了 b 的位置上的 b

  3. 选择一个之前选了 b 没选 a 的位置,和一个之前选了 a 没选 b 的位置,将 a,b 选上,再丢掉一个选了 a,b 的位置上的 a,b

  4. 选择一个什么都没选位置上的 a,b,将他们选上,再选择一个之前选了 b 没选 a 的位置,和一个之前选了 a 没选 b 的位置,将 a,b 丢掉。

列成式子就是:

  1. amaxamin

  2. bmaxbmin

  3. (a+b)maxaminbmin

  4. amax+bmax(a+b)min

然后就可以开六个堆来维护这些式子。

最后,就是板子了。

Code#

#include <bits/stdc++.h>
using namespace std;

inline int read()
{
    int s = 0 , f = 1; char ch;
    while(!isdigit(ch = getchar())) if(ch == '-') f = -1;
    while(isdigit(ch)) s = s * 10 + ch - '0' , ch = getchar();
    return s * f;
}

const int maxn = 200010;

int t , n , k , l , vis[maxn] , a[maxn] , b[maxn];

struct edge
{
	int id , num;
}al[maxn] , bl[maxn];

inline bool cmp(edge x , edge y)
{
	return x.num > y.num;
}

struct qwq
{
	int sum , id;
	inline bool operator<(const qwq &tmp) const
	{
		return sum < tmp.sum;
	}
	
	inline bool operator>(const qwq &tmp) const
	{
		return sum > tmp.sum;
	}
};

priority_queue<qwq , vector<qwq> , less<qwq> > q1 , q2 , q6;
priority_queue<qwq , vector<qwq> , greater<qwq> > q3 , q4 , q5;

/*
q1 -> a_i          q2 -> b_i
q3 -> a_i          q4 -> b_i
q5 -> a_i + b_i    q6 -> a_i + b_i
*/

inline void solve(int i)
{
	if(vis[i] == 0) q6.push({a[i] + b[i] , i});
	if(vis[i] == 1) q2.push({b[i] , i}) , q3.push({a[i] , i});
	if(vis[i] == 2) q1.push({a[i] , i}) , q4.push({b[i] , i});
	if(vis[i] == 3) q5.push({a[i] + b[i] , i});
}

inline void init()
{
	memset(vis , 0 , sizeof(vis));
	while(q1.empty() == 0) q1.pop();
	while(q2.empty() == 0) q2.pop();
	while(q3.empty() == 0) q3.pop();
	while(q4.empty() == 0) q4.pop();
	while(q5.empty() == 0) q5.pop();
	while(q6.empty() == 0) q6.pop();
}

signed main()
{
	t = read();
	while(t--)
	{
		init();
		long long sum = 0 , res = 0;
		//sum当前和,res当前匹配数量. 
		n = read() , k = read() , l = read();
		for(int i = 1;i <= n;i++) a[i] = read() , al[i] = {i , a[i]};
		for(int i = 1;i <= n;i++) b[i] = read() , bl[i] = {i , b[i]};
		sort(al + 1 , al + n + 1 , cmp);
		sort(bl + 1 , bl + n + 1 , cmp);
		for(int i = 1;i <= k;i++)
			sum += al[i].num , vis[al[i].id] = (vis[al[i].id] > 0 ? 3 : 1),
			sum += bl[i].num , vis[bl[i].id] = (vis[bl[i].id] > 0 ? 3 : 2);
		//vis_i == 1 只选 a_i
		//vis_i == 2 只选 b_i
		//vis_i == 3 都选了. 
		for(int i = 1;i <= n;i++)
			res += (vis[i] == 3);
		for(int i = 1;i <= n;i++) solve(i);
		while(res < l)
		{
			long long lsum = -10000000000 , casel = 0;
			
			while(q1.empty() == 0 && vis[q1.top().id] != 2) q1.pop();
			while(q2.empty() == 0 && vis[q2.top().id] != 1) q2.pop();
			while(q3.empty() == 0 && vis[q3.top().id] != 1) q3.pop();
			while(q4.empty() == 0 && vis[q4.top().id] != 2) q4.pop();
			while(q5.empty() == 0 && vis[q5.top().id] != 3) q5.pop();
			while(q6.empty() == 0 && vis[q6.top().id] != 0) q6.pop();
			
			if(q1.empty() == 0 && q3.empty() == 0)
			{
				if(lsum < q1.top().sum - q3.top().sum)
					lsum = q1.top().sum - q3.top().sum , casel = 1;
			}
			
			if(q2.empty() == 0 && q4.empty() == 0)
			{
				if(lsum < q2.top().sum - q4.top().sum)
					lsum = q2.top().sum - q4.top().sum , casel = 2;
			}
			
			if(q1.empty() == 0 && q2.empty() == 0 && q5.empty() == 0)
			{
				if(lsum < q1.top().sum + q2.top().sum - q5.top().sum)
					lsum = q1.top().sum + q2.top().sum - q5.top().sum , casel = 3;
			}
			
			if(q3.empty() == 0 && q4.empty() == 0 && q6.empty() == 0)
			{
				if(lsum < q6.top().sum - q3.top().sum - q4.top().sum)
					lsum = q6.top().sum - q3.top().sum - q4.top().sum , casel = 4;
			}
			
			if(casel == 1)
				vis[q1.top().id] = 3 , vis[q3.top().id] = 0,
				solve(q1.top().id) , solve(q3.top().id),
				q1.pop() , q3.pop();
				
			if(casel == 2)
				vis[q2.top().id] = 3 , vis[q4.top().id] = 0,
				solve(q2.top().id) , solve(q4.top().id),
				q2.pop() , q4.pop();
				
			if(casel == 3)
				vis[q1.top().id] = 3 , vis[q2.top().id] = 3 , vis[q5.top().id] = 0,
				solve(q1.top().id) , solve(q2.top().id) , solve(q5.top().id),
				q1.pop() , q2.pop() , q5.pop();
				
			if(casel == 4)
				vis[q3.top().id] = 0 , vis[q4.top().id] = 0 , vis[q6.top().id] = 3,
				solve(q3.top().id) , solve(q4.top().id) , solve(q6.top().id),
				q3.pop() , q4.pop() , q6.pop();
			
			sum += lsum , res++;
		}
		cout << sum << endl;
	}
    return 0;
}

作者:JiaY19

出处:https://www.cnblogs.com/JiaY19/p/15907207.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   JiaY19  阅读(56)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示