jzoj 2866. 集训队互测 2012Bomb
Posted jz929
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jzoj 2866. 集训队互测 2012Bomb相关的知识,希望对你有一定的参考价值。
Description
给你\(n\)个点,坐标分别为\((xi,yi)\)。从中取出三个点,使得其两两间曼哈顿距离和最大和最小,求最大值和最小值。
对于 100% 的数据, N<=100000 , 0<=Xi,Yi<=10^8
Solution
看完题目后感觉要分类讨论,思考1h后果断暴力O(n^3)。
但是判断了一下n<=500才跑暴力,得了30分。(?10^9过4s?不判50分)
其实可以O(n^2)暴力的。(听说O(n^2)+优化 = 100)
对于第一个最大值,我们可以\(O(n)\)求出。
我们先扫一遍\(n\)个点,可以得到最大和最小的\(x\)以及最大和最小的\(y\)。
然后我们再枚举每个点,而其所组成的三个点的最大值便是\(2 * max(maxx - a[i].x, a[i].x - minx) + 2 * max(maxy - a[i].y, a[i].y - miny)\)
因为它所组成的矩形是最长的长和最长的宽,所以值便是最大的。
这是运用了贪心的思想,可以感性理解一下。
然后我们再求最小值。
这里使用\(O(n^2)\)的方法+优化的。
我们先将点按照\(x\)从小到大排序。
对于三个点:\((x1, y1),(x2, y2),(x3, y3)\)。
\(x1 < x2 < x3\),所以关于\(x\)的答案就应该是:
\((x2 - x1) + (x3 - x2) + (x3 - x1)\)
\(=2 * (x3 - x1)\)
我们发现与\(x2\)无关。
所以我们只需枚举两个点,即可得到有关\(x\)的答案。
而\(y\)呢,我们便只需在线维护一个\(i\) ~ \(j\)的与\(a[i].y,a[j].y\)的差的最小值即可。
\(if (a[j].x - a[i].x >= ans2) break;\)
这个优化正确性显然。
Code
#include <cstdio>
#include <algorithm>
#define N 100010
#define fo(x, a, b) for (int x = a; x <= b; x++)
#define fd(x, a, b) for (int x = a; x >= b; x--)
using namespace std;
struct node{int x, y;}a[N];
int n, m, maxy, miny, up, down, s, s1;
int ans1, ans2 = 2e9;
bool pd;
inline int read()
{
int x = 0; char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return x;
}
inline int cmp(node x, node y) {return x.x < y.x;}
inline int max(int x, int y) {return x > y ? x : y;}
inline int min(int x, int y) {return x < y ? x : y;}
int main()
{
freopen("bomb.in", "r", stdin);
freopen("bomb.out", "w", stdout);
n = read();
a[1].x = read();
maxy = miny = a[1].y = read();
fo(i, 2, n)
{
a[i].x = read(), a[i].y = read();
if (a[i].y > maxy) maxy = a[i].y;
else if (a[i].y < miny) miny = a[i].y;
}
sort(a + 1, a + n + 1, cmp);
ans1 = a[n].x - a[1].x + max(max(maxy - a[1].y, a[1].y - miny), max(maxy - a[n].y, a[n].y - miny));
fo(i, 2, n - 1) ans1 = max(ans1, max(a[n].x - a[i].x, a[i].x - a[1].x) + max(maxy - a[i].y, a[i].y - miny));
fo(i, 1, n)
{
if (n >= 10000 && pd && a[i].x == a[i - 1].x) continue;
if (a[i + 1].y < a[i].y) up = 2e9, down = a[i + 1].y;
else up = a[i + 1].y, down = -2e9;
pd = 0;
fo(j, i + 2, n)
{
if (a[j].x - a[i].x >= ans2) {pd = 1; break;}
s = max(up - a[i].y, abs(up - a[j].y));
s1 = max(a[i].y - down, abs(down - a[j].y));
s = max(min(s, s1), abs(a[i].y - a[j].y));
ans2 = min(ans2, a[j].x - a[i].x + s);
if (a[j].y < a[i].y) down = max(down, a[j].y);
else up = min(up, a[j].y);
}
}
printf("%d\n%d\n", ans1 << 1, ans2 << 1);
return 0;
}
以上是关于jzoj 2866. 集训队互测 2012Bomb的主要内容,如果未能解决你的问题,请参考以下文章
LuoguP4463 [集训队互测2012] calc DP+拉格朗日插值