CF-Round #635-div2-D题
D. Xenia and Colorful Gems
这道题排序二分模拟题。
题目大意:
给你三种颜色的宝石,每个宝石有他的重点。主人公会选择每种颜色的宝石各一个。并且要求这三个宝石的重量差的平方和最小。
假设选的三个宝石的重量分别是x, y, z;
我们要使得下面的式子的值最小:
题目思路:其实就是模拟,只是模拟的过程需要二分来优化。
我们首先把给的重量分别排序下,
然后一个一个来模拟。
我们需要模拟六次。
两次以红宝石为基础,两次以蓝宝石为基础,两次以绿宝石为基础。
交叉进行。
这里举一个例子:
我们以红宝石为基础时,遍历这个红宝石的重量,找到当前红宝石的重量与绿宝石和蓝宝石最接近的。
我们用lower_bound()找到重量最接近的绿宝石(返回的是第一个大于等于的)
用upper_bound()找到重量最接近的蓝宝石(返回的是第一个大于的)
如果lower_bound()返回的是end,说明绿宝石中没有比当前操作红宝石大的,代表我们选取的红宝石重量太大。
如果upper_bound()返回的是begin,说明蓝宝石中第一个就已经比当前操作红宝石大了,代表我们选取的红宝石重量太轻了。
以上这两种情况直接continue就行。
其余情况
我们把upper_bound()返回的索引-1;(因为返回的是第一个大于,有可能前面一个索引是等于的情况,小于也不要紧。)
然后再维护最小值ans.
这里说一下为什么upper_bound()在判断的时候判断的是begin,而不是end。因为如果我们判断end的话,假如现在出现了蓝宝石的最后一个都不能大于当前操作的红宝石的重量,按照判断end的情况,我们就直接continue了。但是这种情况如果恰好是我们的答案最小值。我们就漏掉了(其他情况也不能到达这种情况。)
举个具体的例子:
红宝石重量:1 2
绿宝石重量:3 4
蓝宝石重量:6 7
现在操作这种情况:绿宝石作为基础,当前操作重量是4
蓝宝石作为lower_bound()的判断
红宝石作为upper_bound()的判断
那么lower_bound()返回的是0,也就是蓝宝石重量为6;(第一个大于等于的)
upper_bound()返回的是end,也就是当前绿宝石的操作重量比红宝石的重量全都大。
按照上面的全部都判断end,这个时候直接continue;
最后我们就会得到错误答案,ans = 26
但实际上答案是24;(恰好就是我们continue的这种情况)
选择绿宝石重量为4,蓝宝石重量为6,红宝石重量为2;
所以我们需要判断begin,我们在后面进行了–操作(所以不需要担心到end会不会越界的问题)
还有一个问题:那么我们跳过begin情况会不会漏掉一些情况呢,是不会漏掉的。因为我们执行这个模拟操作执行六次,每种颜色都会被当成基础来执行。跳过begin的原因是当前操作的宝石重量太小了,跳过的begin,会在某一次模拟中当成基础找到对应的最接近的重量。有lower和upper的同时配合,可以得到最佳答案。
这个地方需要想清楚
代码部分:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int nr, nb, ng;
ll ans;
ll square(int a)
{
return 1ll * a * a;
}
void solve(vector<int> a, vector<int> b, vector<int> c)
{
int siz = a.size();
for (int i = 0; i < siz; i++)
{
int t1 = lower_bound(b.begin(), b.end(), a[i]) - b.begin();
int t2 = upper_bound(c.begin(), c.end(), a[i]) - c.begin();
if (t1 == b.size() || !t2)
{
continue;
}
t2--;
ans = min(ans, square(a[i] - b[t1]) + square(a[i] - c[t2]) + square(b[t1] - c[t2]));
}
}
int main()
{
int t;
cin >> t;
while (t--)
{
cin >> nr >> ng >> nb;
vector<int> r(nr);
vector<int> g(ng);
vector<int> b(nb);
for (int i = 0; i < nr; i++)
{
scanf ("%d", &r[i]);
}
for (int i = 0; i < ng; i++)
{
scanf ("%d", &g[i]);
}
for (int i = 0; i < nb; i++)
{
scanf ("%d", &b[i]);
}
sort(r.begin(), r.end());
sort(g.begin(), g.end());
sort(b.begin(), b.end());
ans = 9e18 + 10;
solve(r, b, g);
solve(r, g, b);
solve(b, r, g);
solve(b, g, r);
solve(g, r, b);
solve(g, b, r);
cout << ans << endl;
}
return 0;
}