题解:AT_abc376_e [ABC376E] Max × Sum

题目翻译

给你两个长度为 N N N 的序列 A A A 和 B B B。再给你一个整数 K K K,让你求对于集合 \\lbrace\\ 1,\\ 2,\\ \\dots,\\ N\\ \\rbrace 的每一个长度为 K K K 的子集 S S S,求 \\displaystyle\\ \\left(\\max_{i\\ \\in\\ S}\\ A_i\\right)\\ \\times\\ \\left(\\sum_{i\\ \\in\\ S}\\ B_i\\right) 的最小值。有 T T T 组测试数据。

思路

子集是不一定连续的,在这个问题中,顺序也不重要,所以我们可以把序列按 A A A 从小到大排序。值得注意的是, A i A_i Ai 和 B i B_i Bi 是对应的,所以需要放到一个结构体里面,不然排完序之后就乱了。

排序的好处是我们在计算 A A A 中前 i i i 个元素选出 K K K 个数(第 i i i 个必须选)里面的最大值的时候可以直接用 A i A_i Ai,时间复杂度 O ( 1 ) O(1) O(1)。

然后我们的问题就只剩下一点点了。需要求和的那部分怎么算呢?因为要求最小值,所以肯定希望这个和越小越好。那最小值怎么维护呢?我在比赛的时候想到了动态规划,但是时间复杂度 O ( N ⋅ K ) O(N\cdot K) O(N⋅K),空间复杂度在压维了之后是 O ( K ) O(K) O(K),肯定会超时。

怎么优化呢?前面的思路都没有问题,就卡在这一步了。事实上,有个好东西叫堆,它可以帮助我们解决这个问题。不会手写堆可以用 STL 里面的优先队列。

建一个大根堆,先把 B 1 , B 2 , ... , B K − 1 B_1,B_2,\dots,B_{K-1} B1,B2,...,BK−1 放进去。然后对于 i = K , K + 1 , ... , N i=K,K+1,\dots,N i=K,K+1,...,N,考虑把它放进堆里会不会产生更好的答案。我们维护一个变量 s u m sum sum,它的初始值为 B B B 数组中第 1 1 1 至第 K − 1 K-1 K−1 个元素之和。每一次, B i B_i Bi 入队,用队列中所有数之和乘以最大值(前面说过怎么算)更新答案。然后,我们把堆中最大的那个数(即堆顶)弹出去。 s u m sum sum 的更新方式为:先加上 B i B_i Bi,再减去堆顶元素的值。

于是这样就 AC 了。

相关推荐
飘若随风9 分钟前
C++ STL list
c++·windows·list
PM简读馆1 小时前
Linux C++ 编程死锁详解
linux·开发语言·c++
h^hh2 小时前
洛谷 P1115 最大子段和(前缀和详解)c++
开发语言·c++·算法
我们的五年2 小时前
【Json—RPC框架】:宏定义不受命名空间限制,续行符的错误使用造成的bug
linux·c++
谁怕?一蓑烟雨任平生3 小时前
数据结构——栈和队列
数据结构·c++
梦醒沉醉3 小时前
C++和标准库速成(五)——C风格的数组、std::array、std::vector、std::pair和std::optional
c++
ん贤4 小时前
【数据结构】栈与队列:基础 + 竞赛高频算法实操(含代码实现)
java·数据结构·c++·算法
萧萧玉树4 小时前
设计模式-单一职责
开发语言·c++·设计模式
小林熬夜学编程5 小时前
【高并发内存池】第一弹---深入解析内存池:项目介绍、原理及设计定长内存池全攻略
linux·服务器·c语言·开发语言·c++·算法
郭涤生5 小时前
Chapter 2:auto_《Effective Modern C++》notes
开发语言·c++·笔记