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;
}

浙公网安备 33010602011771号