专栏文章
题解:P12458 [JOI2025 预选赛 R2] 冰淇淋
P12458题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mioy60ka
- 此快照首次捕获于
- 2025/12/03 03:04 3 个月前
- 此快照最后确认于
- 2025/12/03 03:04 3 个月前
题意简述
Alice 和 Bob 在定制冰淇淋,规则如下:
- Alice 先选择一种口味(价格数组 )。
- Bob 接着选择一种蛋筒(价格数组 )。
- Alice 最后选择一种配料(价格数组 )。
冰淇淋总价格 ,得分定义为 。Alice 的目标是最大化得分,Bob 的目标是最小化得分。双方均采取最优策略,计算最终得分。
思路
一个典型的博弈论题目。
游戏分为三个阶段,采用逆向分析可得:
- 首先,当已知 和 ,Alice 会选择 最大化 。
- 然后,当已知 ,Bob 会选择 最小化 Alice 在第 步能获得的最大得分。
- 最后,Alice 会选择 最大化 Bob 在第二步中最小化的得分。
形式化地,定义:
- ,(配料的最小和最大价格)。
- 对于固定 和 ,得分为:
- Bob 的目标:。
- Alice 的目标:。
此时我们注意到,函数 () 在 的不同区间有不同行为:
- :(递减)。
- :(先减后增,最小值在 )。
- :(递增)。
综上,本题策略为:
对于每个 :
-
计算关键点:
- (区间 的上界)。
- (区间 的下界)。
- (区间 的最小值点)。
-
在排序后的 数组中搜索候选 :
- 区间 :取 的最大 。
- 区间 :取 的最小 。
- 区间 :取最接近 的两个 (左侧最大和右侧最小且在 内)。
-
计算每个候选 对应的 ,取最小值作为 。
-
答案取所有 的最大值。
美汁汁()的代码时间~
CPP#include <bits/stdc++.h>
#define Code using
#define by namespace
#define CleverSea std
Code by CleverSea;
const int N = 2e5 + 10;
long long A[N], B[N], C[N];
int main() {
long long X, Y, Z, P;
scanf("%lld %lld %lld %lld", &X, &Y, &Z, &P);
for (int i = 0; i < X; i++) {
scanf("%lld", &A[i]);
}
for (int i = 0; i < Y; i++) {
scanf("%lld", &B[i]);
}
for (int i = 0; i < Z; i++) {
scanf("%lld", &C[i]);
}
sort(B, B + Y);
// 计算配料的最小值D和最大值E
long long minC = C[0], maxC = C[0];
for (int i = 1; i < Z; i++) {
if (C[i] < minC) minC = C[i];
if (C[i] > maxC) maxC = C[i];
}
long long ans = 0;
// 遍历每种口味
for (int i = 0; i < X; i++) {
long long key1 = P - maxC - A[i]; // 区间I上界
long long key2 = P - minC - A[i]; // 区间III下界
vector<long long> cf; // 存储候选得分
// 候选1:区间I中最大的Bj(<=key1)
int pos1 = upper_bound(B, B + Y, key1) - B;
if (pos1 > 0) {
long long Bj = B[pos1 - 1];
long long s = A[i] + Bj;
long long fv1 = llabs(s + minC - P);
long long fv2 = llabs(s + maxC - P);
long long fv = max(fv1, fv2);
cf.push_back(fv);
}
// 候选2:区间III中最小的Bj(>=key2)
int pos3 = lower_bound(B, B + Y, key2) - B;
if (pos3 < Y) {
long long Bj = B[pos3];
long long s = A[i] + Bj;
long long fv1 = llabs(s + minC - P);
long long fv2 = llabs(s + maxC - P);
long long fv = max(fv1, fv2);
cf.push_back(fv);
}
// 计算区间II的理想点s0
double s0v = (2.0 * P - minC - maxC) / 2 - A[i];
// 候选3:区间II中小于等于s0v的最大Bj
long long flov = (long long)floor(s0v);
int posl = upper_bound(B, B + Y, flov) - B;
if (posl > 0) {
long long can = B[posl - 1];
if (can > key1 && can < key2) { // 在开区间内
long long s = A[i] + can;
long long fv = max(llabs(s + minC - P), llabs(s + maxC - P));
cf.push_back(fv);
}
}
// 候选4:区间II中大于等于s0v的最小Bj
long long ceiv = (long long)ceil(s0v);
int posh = lower_bound(B, B + Y, ceiv) - B;
if (posh < Y) {
long long can = B[posh];
if (can > key1 && can < key2) { // 在开区间内
long long s = A[i] + can;
long long fv = max(llabs(s + minC - P), llabs(s + maxC - P));
cf.push_back(fv);
}
}
// 确保候选列表非空(理论上不会为空,但还是检查一下)
if (!cf.empty()) {
long long minv = *min_element(cf.begin(), cf.end());
if (minv > ans) {
ans = minv;
}
}
}
printf("%lld\n", ans);
return 0;
}
其中排序 数组 ,遍历 数组,每个元素在 上二分查找 , 个元素 ,总复杂度 。
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...