【C++贪心】P9965 [THUPC 2024 初赛] 转化|省选-

本文涉及知识点

C++贪心

[THUPC 2024 初赛] 转化

题目背景

小 E 在玩 Somzig 游戏的时候因为操作时间不够绷不住了,于是就有了这个题。

题目描述

小 E 有 n n n 种颜色的球,其中第 i i i 种有 a i a_i ai 个。有两类工具,第一类可以把一个指定颜色的球变成一个任意颜色的球;第二类可以把一个指定颜色的球变成两个这种颜色的球。一个变化之后的球也可以通过工具产生新的变化。关于第 i i i 种颜色的第一类工具有 b i b_i bi 个,第二类工具有 c i c_i ci 个。小 E 想知道,如果每一工具最多只能使用一次,那么对于每种颜色 i i i,第 i i i 种颜色的球最后最多能有多少个。以及,小 E 最后最多能有多少个球。

输入格式

第一行一个正整数 n n n

第二行 n n n 个整数,其中第 i i i 个表示 a i a_i ai

第三行 n n n 个整数,其中第 i i i 个表示 b i b_i bi

第四行 n n n 个整数,其中第 i i i 个表示 c i c_i ci

输出格式

第一行 n n n 个整数,其中第 i i i 个表示如果每个工具最多使用一次,那么小 E 最后第 i i i 种颜色的球最多有多少个。

第二行一个整数,表示如果每个工具最多使用一次,那么小 E 最后最多能有多少个球。

样例 #1

样例输入 #1

2
1 2
1 2
1 0

样例输出 #1

4 3
4

提示

子任务

保证 1 ≤ n ≤ 351493 1\le n \le 351493 1n351493

保证 0 ≤ a i , b i , c i ≤ 1 0 9 0\le a_i,b_i,c_i\le 10^9 0ai,bi,ci109

题目使用协议

来自 THUPC2024(2024年清华大学学生程序设计竞赛暨高校邀请赛)初赛。

  1. 任何单位或个人都可以免费使用或转载本仓库的题目;

  2. 任何单位或个人在使用本仓库题目时,应做到无偿、公开,严禁使用这些题目盈利或给这些题目添加特殊权限;

  3. 如果条件允许,请在使用本仓库题目时同时提供数据、标程、题解等资源的获取方法;否则,请附上本仓库的 github 地址。

贪心

sab = ∑ \sum min(a[i],b[i]) 。

计算第 i1种颜色最多多少个。

枚举各颜色j:
如果b[j]为0,d[j] = 0。
如果a[j]等于0,且sab>0 d[j] = min(1+c[j],b[j])-1。
如果sab=0,d[j] = 0。
如果a[j]不等于0 。d[j] = min(a[j]+c[j],b[j])
x1 = ∑ \sum d -d[i1]
x1+= a[i1]
如果x1 > 0 x1 += c[i1]。
x1就是颜色i1的最多球数量。
性质一:如果sab>0,假定此球最初在i2,最终在i3,如果b[j]不为0。则i2 → \rightarrow j → \rightarrow i3。

最多球

ans = 0 sab=0
按{a,b,c}降序排序。
先处理a>0
ans += (a+c)sab +=min(a+c,b)
再处理a为0,必须sab > 0
ans += c sab +=min(1+c,b)-1

逻辑

a>0,c全部生效,且sab增加或不变。
a=0,b>0,如果sab>0,c全部生效,且sab增加或不变。
a=0,b=0如果sab>0,c全部生效,且sab–。

代码

核心代码

#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>

#include <bitset>
using namespace std;



template<class T = int>
vector<T> Read(int n,const char* pFormat = "%d") {
	vector<T> ret(n);
	for(int i=0;i<n;i++) {
		scanf(pFormat, &ret[i]);	
	}
	return ret;
}

template<class T = int>
vector<T> Read( const char* pFormat = "%d") {
	int n;
	scanf("%d", &n);
	vector<T> ret;
	T d;
	while (n--) {
		scanf(pFormat, &d);
		ret.emplace_back(d);
	}
	return ret;
}

string ReadChar(int n) {
	string str;
	char ch;
	while (n--) {
		do
		{
			scanf("%c", &ch);
		} while (('\n' == ch));
			str += ch;
	}
	return str;
}
template<class T1,class T2>
void ReadTo(pair<T1, T2>& pr) {
	cin >> pr.first >> pr.second;
}

class Solution {
public:
	vector<long long> Ans(const int N, vector<int>& a, vector<int>& b, vector<int>& c)
	{
		auto ans = Ans1(N, a, b, c);
		ans.emplace_back(Ans2(N, a, b, c));
		return ans;
	}
	vector<long long> Ans1(const int N, vector<int>& a, vector<int>& b, vector<int>& c)
	{
		long long sab = 0;
		for (int i = 0; i < N; i++) {
			sab += min(a[i], b[i]);
		}
		vector<int> d(N);
		for (int i = 0; i < N; i++) {
			if (0 == b[i]) { continue; }
			if (0 != a[i]) { d[i] = min(b[i], a[i] + c[i]); continue; }
			if (0 == sab) { continue; }
			d[i] = min(1 + c[i], b[i]) - 1;
		}
		vector<long long> ans(N);
		long long sum = accumulate(d.begin(), d.end(), 0LL);
		for (int i = 0; i < N; i++) {
			ans[i] = sum - d[i] + a[i];
			if (ans[i] > 0) { ans[i] += c[i]; }
		}
		return ans;
	}
	long long Ans2(const int N, vector<int>& as, vector<int>& bs, vector<int>& cs)
	{
		vector<tuple<int, int, int>> abc;
		for (int i = 0; i < N; i++) {
			abc.emplace_back(as[i], bs[i], cs[i]);
		}
		sort(abc.begin(), abc.end());
		long long sab = 0, ans = 0;
		while (abc.size() && (get<0>(abc.back()) > 0)) {
			auto [a, b, c] = abc.back();
			ans += a + c;
			sab += min(a + c, b);
			abc.pop_back();
		}
		while (abc.size() && (sab > 0)) {
			auto [a, b, c] = abc.back();
			ans += c;
			sab += min(1 + c, b) - 1;
			abc.pop_back();
		}
		return ans;
	}
};

int main() {
#ifdef _DEBUG
	freopen("a.in", "r", stdin);
#endif // DEBUG
	int n=0;
	scanf("%d", &n);
	auto a = Read<int>(n);
	auto b = Read<int>(n);
	auto c = Read<int>(n);
	auto res = Solution().Ans(n,a,b,c);
#ifdef _DEBUG
/*		printf("n=%d", n);	
		Out(a, "a=");
		Out(b, ",b=");
		Out(c, ",c=");	*/	
#endif	
		for (int i = 0; i < n; i++) {
			cout << res[i] << " ";
	}
	cout << std::endl << res.back() << std::endl;		
	return 0;
}

单元测试

int n;
		vector<int> a, b, c;
		TEST_METHOD(TestMethod11)
		{
			n = 2,a = { 1,2 }, b = { 1,2 }, c = { 1,0 };
			auto res = Solution().Ans(n,a,b,c);
			AssertEx({ 4,3,4 }, res);
		}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

软件架构师何志丹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值