usaco 2021DEC 银组第3题
作者:互联网
[USACO21DEC] Closest Cow Wins S
题目描述
Farmer John 沿着一条高速公路拥有一个很长的农场,可以被看作类似于一维数轴。沿着农场有 KKK 块草地(1≤K≤2⋅1051 \leq K \leq 2\cdot 10^51≤K≤2⋅105);第 iii 块草地位于位置 pip_ipi 并具有美味值 tit_iti(0≤ti≤1090\le t_i\le 10^90≤ti≤109)。Farmer John 的死对头 Farmer Nhoj 已经将他的 MMM 头奶牛(1≤M≤2⋅1051 \leq M \leq 2\cdot 10^51≤M≤2⋅105)放在了位置 f1…fMf_1 \ldots f_Mf1…fM 。所有这些 K+MK+MK+M 个位置均是 [0,109][0,10^9][0,109] 范围内的不同整数。
Farmer John 需要选择 NNN(1≤N≤2⋅1051\le N\le 2\cdot 10^51≤N≤2⋅105)个位置(不一定是整数)放置他的奶牛。这些位置必须与 Farmer Nhoj 的奶牛已经占用的位置不同,但是 Farmer John 可以将他的奶牛放在与草地相同的位置。
拥有最靠近某个草地的奶牛的农夫拥有这一草地。如果来自两方农夫的两头奶牛距这一草地相等,则 Farmer Nhoj 拥有该草地。
给定 Farmer Nhoj 的奶牛的位置以及草地的位置和美味值,求 Farmer John 的奶牛以最优方式放置时可以达到的最大总美味值。
输入格式
输入的第一行包含 KKK、MMM 和 NNN。
以下 KKK 行每行包含两个空格分隔的整数 pip_ipi 和 tit_iti。
以下 MMM 行每行包含一个整数 fif_ifi。
输出格式
输出一个整数,表示最大总美味值。注意这个问题的答案可能无法用 32 位整数型存储,你可能需要使用 64 位整数型(例如,C 或 C++ 中的 “long long”)。
输入输出样例
输入 #1
6 5 2
0 4
4 6
8 10
10 8
12 12
13 14
2
3
5
7
11
输出 #1
36
说明/提示
【样例解释】
如果 Farmer John 将奶牛放在位置 11.511.511.5 和 888 则他可以得到总美味值 10+12+14=3610+12+14=3610+12+14=36。
解析:
用贪心解决。开一个优先队列,把每个区间放进去,优先队列按照当前区间再放一头牛的收益,从大到排序。这样我们相当于每次决策的时候,都选择一个最划算的区间,尽量用手里现在这头牛,获得最大的价值。当一个区间从优先队列里面取出来的时候,我们看一下,如果这个区间是第一次被取出来,我们就把它的 valuevaluevalue ,改成 all−valueall-valueall−value 再放回去。表示这个区间已经放过一头牛了,如果再放一头牛,它的价值就是放两头牛价值的总和,那么第二头牛的价值就是 all−valueall-valueall−value 。这样一直贪心就可以了。
code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN = 2e5 + 5;
struct Grass {
ll p, t;//位置,价值
ll l, r;//想占据当前草地,需要放牛的区间,都是开区间
bool operator<(const Grass &a) const {
return p < a.p;
}
} g[MAXN];
struct Node {
ll value, all, cnt;//在当前区间内再选一头牛的价值,区间总价值,已经拿了几次了
Node(ll value, ll all, ll cnt) : value(value), all(all), cnt(cnt) {}
bool operator<(const Node &a) const {
return value < a.value;
}
};
ll k, m, n;//草地,敌人牛的数量,自己牛的数量
ll f[MAXN];//敌人的牛的位置
ll p[MAXN << 2], pc;//当前段内关键点,关键点的个数
ll dp[MAXN];
priority_queue<Node> q;
//进行分组
void work() {
ll all = 0;//当前组内总价值
ll pi = 1;//下一个还没分配的草地
//第一头敌人的牛前面的,都可以用一头牛直接拿下
while (pi <= k && g[pi].p < f[1]) {
all += g[pi].t;
pi++;
}
q.push(Node(all, all, 0));
for (int i = 2; i <= m; ++i) {
//处理f[i-1]到f[i]之间的草
all = pc = 0;
ll left = f[i - 1], right = f[i];//左边界,右边界
ll from = pi;//本组内第1块草
while (pi <= k && g[pi].p < right) {
ll ra = min(g[pi].p - left, right - g[pi].p);//当前半径
g[pi].l = g[pi].p - ra;
g[pi].r = g[pi].p + ra;
if (g[pi].l != left) {
p[pc++] = g[pi].l;
}
if (g[pi].r != right) {
p[pc++] = g[pi].r;
}
all += g[pi].t;
pi++;
}
if (from == pi) {
//这一块内没有草
continue;
}
//对于每个关键点,看看把牛放在关键点左边一点点怎么样
p[pc++] = right;//右端点也算一个关键点
sort(p, p + pc);
ll tt = 0;
//尺取计算放在每个关键点的答案
ll tl = from, tr = from - 1, w = 0;
for (int j = 0; j < pc; ++j) {
ll pos = p[j];
while (tr + 1 < pi && pos > g[tr + 1].l) {
tr++;
w += g[tr].t;
}
while (tl < pi && pos > g[tl].r) {
w -= g[tl].t;
tl++;
}
tt = max(tt, w);
}
q.push(Node(tt, all, 0));
}
//最后一个敌人的牛的后面的牛,都可以用一只牛搞定
all = 0;
while (pi <= k) {
all += g[pi].t;
pi++;
}
q.push(Node(all, all, 0));
}
int main() {
scanf("%lld%lld%lld", &k, &m, &n);
for (int i = 1; i <= k; ++i) {
scanf("%lld%lld", &g[i].p, &g[i].t);
}
for (int i = 1; i <= m; ++i) {
scanf("%lld", &f[i]);
}
sort(g + 1, g + k + 1);
sort(f + 1, f + m + 1);
work();
ll ans = 0;
while(n>0 && !q.empty()){
Node t = q.top();
q.pop();
ans+=t.value;
if(t.cnt==0 && t.value!=t.all){
t.cnt++;
t.value = t.all-t.value;
q.push(t);
}
n--;
}
printf("%lld\n",ans);
return 0;
}
标签:10,2021DEC,草地,ll,value,usaco,Farmer,银组,pi 来源: https://blog.csdn.net/weixin_43894506/article/details/122619054