CF1336B Xenia and Colorful Gems

题目大意

你有$3$个数组,分别是$\texttt{r, g, b}$,长度分别是$n_r, n_b, n_g$

你需要在这三个数组中选择一个数,设你选择的三个数为$x, y, z$,则你要使$(x-y)^2+(y-z)^2+(z-x)^2$最小

多组数据,$1 \leq n_r, n_b, n_g \leq 10^5$,值域$1 \leq r_i, b_i, g_i \leq 10^9$

分析

首先我们考虑枚举其中一个数,假设我们枚举的是$r$数组。

对于一个数$x$,在某一个数组(假设是$z$)满足$(x-y)^2$最小的$y$一定是$x$在$z$内的前驱或后继。

于是对于每一个$r_i$,我们找到$r_i$在$g$中的前驱和后继,记为$gr_0, gr_1$,再找到$gr_0, gr_1$在$b$里的前驱后继,记为$bl_0, bl_1, bl_2, bl_3$,那么答案就在$f(r_i, gr_0, bl_0), f(r_i, gr_0, bl_1), \cdots, f(r_i, gr_1, bl_3)$中。(其中$f(x, y, z)$表示$1 \leq n_r, n_b, n_g \leq 10^5$)

但是这种可能会有缺漏, 我们可能漏掉了某些情况,例如下面这个例子

1
2
3
4
5
1
2 2 2
1 2
3 4
6 7

。我们会选择$2, 3, 6$而正确答案应该是$2, 4, 6$。

于是,我们考虑对$r, g, b$都做一遍上面这个过程,就能得到正确的答案了。

时间复杂度$\mathcal{O}(n \log n)$

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <bits/stdc++.h>

#define ll long long
#define sum(a, b, mod) (((a) + (b)) % mod)

const int Max = 2e9;
const int Min = -1e9;
const int MaxN = 2e5 + 10;

ll n, m, k, ans;
std::set<ll> R, G, B;
ll r[MaxN], g[MaxN], b[MaxN];

ll sqr(ll x) { return x * x; }

ll sub(ll x, std::set<ll> &y)
{
if (x == 2000000000) return x;
return *y.upper_bound(x);
}

ll pre(ll x, std::set<ll> &y)
{
ll res = *y.lower_bound(x);
if (x == -1000000000) return x;
if (res > x) res = *(--y.lower_bound(x));
return res;
}

void init()
{
ans = 0x7f7f7f7f7f7f7f7fll;
R.clear(), R.insert(-1e9), R.insert(2e9);
G.clear(), G.insert(-1e9), G.insert(2e9);
B.clear(), B.insert(-1e9), B.insert(2e9);
}

int main()
{
int T;
scanf("%d", &T);
while (T--)
{
init();
scanf("%lld%lld%lld", &n, &m, &k);
for (int i = 1; i <= n; i++)
scanf("%lld", &r[i]), R.insert(r[i]);
for (int i = 1; i <= m; i++)
scanf("%lld", &g[i]), G.insert(g[i]);
for (int i = 1; i <= k; i++)
scanf("%lld", &b[i]), B.insert(b[i]);
for (int i = 1; i <= n; i++)
{
ll gr[2] = {}, bl[4] = {};
gr[0] = pre(r[i], G), gr[1] = sub(r[i], G);
bl[0] = pre(gr[0], B), bl[1] = sub(gr[0], B);
bl[2] = pre(gr[1], B), bl[3] = sub(gr[1], B);
for (int j = 0; j < 2; j++)
{
for (int l = 0; l < 4; l++)
if (gr[j] != Max && gr[j] != Min && bl[l] != Max && bl[l] != Min)
ans = std::min(ans, sqr(r[i] - gr[j]) + sqr(gr[j] - bl[l]) + sqr(bl[l] - r[i]));
}
}
for (int i = 1; i <= m; i++)
{
ll gr[2] = {}, bl[4] = {};
gr[0] = pre(g[i], R), gr[1] = sub(g[i], R);
bl[0] = pre(gr[0], B), bl[1] = sub(gr[0], B);
bl[2] = pre(gr[1], B), bl[3] = sub(gr[1], B);
for (int j = 0; j < 2; j++)
{
for (int l = 0; l < 4; l++)
if (gr[j] != Max && gr[j] != Min && bl[l] != Max && bl[l] != Min)
ans = std::min(ans, sqr(g[i] - gr[j]) + sqr(gr[j] - bl[l]) + sqr(bl[l] - g[i]));
}
}
for (int i = 1; i <= k; i++)
{
ll gr[2] = {}, bl[4] = {};
gr[0] = pre(b[i], R), gr[1] = sub(b[i], R);
bl[0] = pre(gr[0], G), bl[1] = sub(gr[0], G);
bl[2] = pre(gr[1], G), bl[3] = sub(gr[1], G);
for (int j = 0; j < 2; j++)
{
for (int l = 0; l < 4; l++)
if (gr[j] != Max && gr[j] != Min && bl[l] != Max && bl[l] != Min)
ans = std::min(ans, sqr(b[i] - gr[j]) + sqr(gr[j] - bl[l]) + sqr(bl[l] - b[i]));
}
}
printf("%lld\n", ans);
}
return 0;
}
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×