题意:
给出3个序列各有:\(n_r,n_g,n_g\) 个。现在在每个序列中选择一个数:\(x,y,z\),使得 \((x-y)^2+(x-z)^2+(y-z)^2\) 最小,求出该最小值。
数据范围:\(1≤n_r,n_g,n_b≤10^5,1≤r_i≤109,1≤g_i≤10^9,1≤b_i≤10^9\)
分析:
1.官方题解思路:
首先,大概思路是:枚举一个值,然后可以求出另外两个。
假定:\(r_i\leq g_i \leq b_i\),那么 \(r_i\) 和 \(b_i\) 必然是越接近 \(g_i\) ,整个的值越小。因此,可以借助二分来求出 \(r_i\) 和 \(b_i\)。
按照分析,有六种可能的排列顺序,枚举进行处理即可。
反思:大概思路想到了,但就是没有想到可以按顺序取分情况处理。
代码 \(1\):
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int r[N],g[N],b[N];
ll ans;
ll get(int x,int y,int z)
{
return 1LL*(x-y)*(x-y)+1LL*(x-z)*(x-z)+1LL*(y-z)*(y-z);
}
void solve(int a[],int c[],int d[],int x,int y,int z)
{
for(int i=1;i<=y;i++)
{
int t1=lower_bound(a+1,a+1+x,c[i])-a;
int t2=lower_bound(d+1,d+1+z,c[i])-d;
if(t1>x||t1<=x&&a[t1]>c[i])
t1--;
if(t1>=1&&t1<=x&&t2>=1&&t2<=z)
{
ll res=get(a[t1],c[i],d[t2]);//cout<<"res="<<res<<endl;
ans=min(ans,res);
}
}
}
int main()
{
int t,nr,ng,nb;
scanf("%d",&t);
while(t--)
{
ans=3e18;
scanf("%d%d%d",&nr,&ng,&nb);
for(int i=1;i<=nr;i++)
scanf("%d",&r[i]);
for(int i=1;i<=ng;i++)
scanf("%d",&g[i]);
for(int i=1;i<=nb;i++)
scanf("%d",&b[i]);
sort(r+1,r+1+nr);
sort(g+1,g+1+ng);
sort(b+1,b+1+nb);
for(int i=1;i<=6;i++)
{
if(i==1)
solve(r,g,b,nr,ng,nb);
else if(i==2)
solve(b,g,r,nb,ng,nr);
else if(i==3)
solve(g,r,b,ng,nr,nb);
else if(i==4)
solve(b,r,g,nb,nr,ng);
else if(i==5)
solve(g,b,r,ng,nb,nr);
else
solve(r,b,g,nr,nb,ng);
}
printf("%lld\n",ans);
}
return 0;
}