首先,很显然,要让 ( x − y ) 2 + ( y − z ) 2 + ( x − z ) 2 (x-y)^2+(y-z)^2+(x-z)^2 (x−y)2+(y−z)2+(x−z)2 的值尽可能小, x , y , z x,y,z x,y,z 三个值就要尽可能接近。
于是我们考虑,枚举其中一种宝石的所有重量,然后在另外两种宝石的重量中找到最接近它的值,最后找到最小的答案。
为了便于枚举所有情况,我们可以确定下
x
,
y
,
z
x,y,z
x,y,z 的大小关系然后进行枚举。
举个栗子:当我们令
x
≤
y
≤
z
x \le y \le z
x≤y≤z 时,我们可以先在第一个数组中枚举重量
x
x
x ,在第二个数组中找到最接近
x
x
x 且大于等于
x
x
x 的值
y
y
y,在第三个数组中找到最接近
y
y
y 且大于等于
y
y
y 的值
z
z
z。然后计算答案,并在所有的答案中取最小值。
但是由于
x
,
y
,
z
x,y,z
x,y,z 的大小关系不确定,我们需要枚举它们的
6
6
6 种大小关系,分别是
x
≤
y
≤
z
x \le y \le z
x≤y≤z
x
≤
z
≤
y
x \le z \le y
x≤z≤y
y
≤
x
≤
z
y \le x \le z
y≤x≤z
y
≤
z
≤
x
y \le z \le x
y≤z≤x
z
≤
x
≤
y
z \le x \le y
z≤x≤y
z
≤
y
≤
x
z \le y \le x
z≤y≤x
当然,不管是用双指针还是二分都要先排序。
由于要多次用到相同的计算,不妨把枚举和计算的过程放到函数里。然后记得开 long long
。
我的做法是双指针,所以没有用 upper_bound
和 lower_bound
。
每次找较小值和较大值的部分时间复杂度是 O ( n ) O(n) O(n) 的,排序的时间复杂度是 O ( n log n ) O(n \log n) O(nlogn),所以最终的时间复杂度是 O ( n log n ) O(n \log n) O(nlogn)。
代码如下:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 5;
long long r[maxn], g[maxn], b[maxn];
long long ans;
long long calc(long long x, long long y, long long z)
{
return (x-y)*(x-y)+(y-z)*(y-z)+(x-z)*(x-z);
}
void solve(long long *x, long long *y, long long *z, int nx, int ny, int nz)
{
int p1 = 0, p2 = 0;
for(int i = 1; i <= nx; i++)
{
while(p1 <= ny && y[p1] <= x[i]) p1++; //找最接近的较小值
while(p2 <= nz && z[p2] < x[i]) p2++; //找最接近的较大值
if(p1 - 1 != 0 && p2 != nz + 1) //较小值和较大值都能找到
ans = min(ans, calc(x[i], y[p1 - 1], z[p2]));
}
return;
}
void work()
{
ans = 0x7fffffffffffffff; //CF的C++11的编译器不支持limits.h中的LONG_LONG_MAX
int nr, ng, nb;
scanf("%d%d%d", &nr, &ng, &nb);
for(int i = 1; i <= nr; i++) scanf("%lld", r + i);
for(int i = 1; i <= ng; i++) scanf("%lld", g + i);
for(int i = 1; i <= nb; i++) scanf("%lld", b + i);
sort(r + 1, r + nr + 1);
sort(g + 1, g + ng + 1);
sort(b + 1, b + nb + 1);
//枚举所有可能的大小关系
solve(r, g, b, nr, ng, nb);
solve(r, b, g, nr, nb, ng);
solve(g, r, b, ng, nr, nb);
solve(g, b, r, ng, nb, nr);
solve(b, r, g, nb, nr, ng);
solve(b, g, r, nb, ng, nr);
printf("%lld\n", ans);
return;
}
signed main()
{
int T;
scanf("%d", &T);
while(T--)
work();
return 0;
}