Loading

luogu P2707 Facer 帮父亲

题目大意

\(n\)个地点,每个风景点有一个票价\(x\)
当票价为\(x\)时利润为\(a_ix-b_ix^2\)

推导过程

\(f_i(x)\)表示在第\(i\)个风景点时,门票价格为\(x\)的利润
\(f_i(x)=-b_ix^2+a_ix\)
那么增加\(1\)票价的收益为
\(f_i(x+1)=-b_i(x+1)^2+a_i(x+1)=f_i(x)+a_i-2b_ix-b_i\)
变形得到
\(f_i(x+1)-f_i(x)=a_i-2b_ix-b_i\)

解法

根据上面可以知道,当\(x\)\(1\)时,\(f_i(x)=a_i-b_i\)
所以我们可以把所有\(a_i-b_i\)丢到大根堆中,每次取收益最大的一个,并将\(f(x+1)-f(x)\)入堆
(相当于每个风景点票价都为\(0\),将票价增加的收入)
若 堆顶小于等于\(0\) 或 增加\(k\)次 ,则停止操作
复杂度\(O(k\log k)\)

注: 可以将这一过程看作一个二次函数,收益看作斜率,为正数时在对称轴左侧

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>

#define x first
#define y second

using namespace std;

typedef long long LL;
typedef pair<int,int> PII;

const int N = 1e5+10;

int n , k;
priority_queue<PII> q;

int main() {
	scanf("%d%d" , &n , &k);
	for(int i = 1 ; i <= n ; i ++) {
		int a , b;
		scanf("%d%d" , &a , &b);
		q.push({a-b,b});
	}
	
	LL res = 0;
	while(k-- && q.size()) {
		PII t = q.top(); q.pop();
		if(t.x <= 0) break;
		res += t.x; t.x -= 2*t.y;
		q.push(t);
	}
	printf("%lld\n" , res);
	return 0;
}
posted @ 2025-09-07 16:44  lyr2023  阅读(9)  评论(0)    收藏  举报