蓝桥杯2023年B组-试题I-最大开支

1.题目

2.题解

2.1 贪心 + 堆

思路

由于如下图公式所示:

  1. 要获取的是最大值(最坏情况), 故如果increase增量小于零则没有必要讨论(存在刚开始由于b较大使得增量大于零,而k小于0,后面由于x增大导致增量为负值)
  2. 可利用贪心局部最优(每次选择加人时,均是选择增量最大的一组),实现全局最优(最大值)
  3. 为了方便每次取最大值,选择使用大根堆自动排序,每次只要取顶部值即可
  4. 计算得到每次增量和各个参数的关系: increase = k + b (x=1) / ((x+1)k + b)(x+1) - (xk + b)x = k(2x+1) + b; (x>1)

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
struct Node {
	int k, b, x, increase;
	Node(int k, int b, int x, int increase) : k(k), b(b), x(x), increase(increase){}
	bool operator <(const Node& other) const{
		return increase < other.increase;
	}
};
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	int n, m;
	cin >> n >> m;
	priority_queue<Node> pq;
	for (int i = 0; i < m; i++){
		Node node(0,0,0,0);
		cin >> node.k >> node.b;
		node.increase = node.k + node.b;
		// 初始化,计算初次所有利润大于 0的(便于第一次选择), 利用大根堆性质增幅最大的放在顶部(贪心,局部最优获取全局最优) 
		if(node.k + node.b > 0){
			node.x = 1;
			pq.push(node);
		}
	}
	
	ll money = 0; 
	for (int person = 0; person < n && !pq.empty(); person++){
		Node node = pq.top();
		pq.pop();
		money += node.increase;
		// 下一次的增幅, ((x+1)*k + b)(x+1) - (x*k + b)x = k(2x+1) + b;  
		node.increase =  (2*node.x + 1) * node.k + node.b;
		if(node.increase > 0){
			node.x += 1;
			pq.push(node);
		} 
	}
	
	cout << money;
	return 0; 
} 
posted @   DawnTraveler  阅读(42)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示