题目来源:NEFU OJ-2175.熬夜的惩罚
题目描述
卡迪亚得到你给他的答案,就蹦跶蹦跶地去下载游戏了,不过由于游戏太多,一直到晚上12点才下载好。看着这么多好玩的游戏,哪还有心情去睡觉啊,于是悄悄关上房门玩起了游戏。
玩着玩着,就到了凌晨5点,这下完蛋了,早上8点还有课呢!!! 于是赶紧倒下去睡觉了(玩了这么久游戏哪可能说睡着就睡着啊),果然,第二天早上上网课卡迪亚睡着了,更巧的是,还被他妈妈逮了个正着,妈妈斥责道:还睡觉?你是啥都会了吗?来,给你写一道题。
题目说:一个平面中有n个点,保证点不重合,任意三点不共线,并且这n个点构成的一定是凸边形,这些点按顺时针顺序从1到n编号。现在告诉你1到n每个点的坐标(xi) (yi)。如果有两个点p1,p2,其中p1=(x1,y1),p2=(x2,y2) ,定义这两点的特殊距离
d(p1,p2)=|x1−x2|+|y1−y2|,
现在再告诉你需要在这n个点中任意选择k(k≥3)个点,请你找出k个点构成的凸边形在特殊距离公式下的最大周长,其中周长C=d(p1,p2)+d(p2,p3)+…+d(pk,p1)。
为了惩罚你,妈妈让你把所有可能的k的结果都求出来,即求出所有k在[3~n]取值时的答案C。
注意:k个点构成的一定要是凸边形,且边不能够相交,边也必须是直线。
输入描述
第一行一个整数表示点的数量n (3≤n≤3⋅1e5)
之后n行,每行两个整数,分别表示第i个点的坐标xi,yi (−1e8≤xi,yi≤1e8)
ps:点集是凸的,所有点都是不同的,点是按顺时针顺序排列的,不会有三个共线点。
输出描述
共一行,分别输出k的取值从3到n时的的每一个结果,每个数之间有一个空格,最后一个数后没有空格。
输入样例1
4
2 4
4 3
3 0
1 3
输出样例1
12 14
输入样例2
3
0 0
0 2
2 0
输出样例2
8
来源
Kadia
OP
感谢学长(大概是)的标程,拍出了自己的bug。
思路
此题中的特殊周长的定义以及凸形的限定,使得n个点构成的凸形周长即为能框住这n个点的最小矩形的周长(该矩形边平行于坐标轴)。
先讨论
k
>
=
4
k>=4
k>=4时的情况:
如果
C
5
>
C
4
C_5>C_4
C5>C4,即说明
C
4
C_4
C4选择的4个点并不是周长最长的点,因为可以选择
C
5
C_5
C5时的第五个点来撑大矩形;
所以
C
4
=
C
5
=
.
.
.
=
C
n
C_4=C_5=...=C_n
C4=C5=...=Cn,即这些k的取值中,结果相同,均是框住所有点的矩形周长;(通俗来说,至少需要四个点来撑住矩形的四个边)
此时结果为
2
∗
(
X
m
a
x
−
X
m
i
n
+
Y
m
a
x
−
Y
m
i
n
)
2*(X_{max}-X_{min}+Y_{max}-Y_{min})
2∗(Xmax−Xmin+Ymax−Ymin);
k
=
3
k=3
k=3时:
对于每一个点,有其参与的最大矩形只有四种情况:
以其为右下顶点,Ymax与Xmin为两边所在直线;
以其为左下顶点,Ymax与Xmax为两边所在直线;
以其为右上顶点,Ymin与Xmin为两边所在直线;
以其为左上顶点,Ymin与Xmax为两边所在直线;
对于每一个点遍历比较即可。
曾经的错误想法及hack数据:本想用最大矩形的一条边作为k=3时矩形的一边,再寻找另一边的可行最大长度(即结果与最大矩形等宽或等高)
hack数据如下
5
74 -44
21 86
-100 23
62 -70
36 -77
正确答案应为636 674 674
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int n,i;
ll gx,gy,xi=1e9+1,yi=1e9+1,xm=-1e9-1,ym=-1e9-1;
static ll x[300005],y[300005];
cin>>n;
for(i=1;i<=n;i++)
{
scanf("%lld%lld",&gx,&gy);
x[i]=gx,y[i]=gy;
xi=min(xi,gx),yi=min(yi,gy),xm=max(xm,gx),ym=max(ym,gy);
}
//if(n==3)printf("%lld",2*(xm-xi+ym-yi));//并不需要对n==3特判
//else
{
ll now=0;
for(i=1;i<=n;i++)
{
now=max(xm-x[i]+ym-y[i],now);
now=max(x[i]-xi+ym-y[i],now);
now=max(xm-x[i]+y[i]-yi,now);
now=max(x[i]-xi+y[i]-yi,now);
}
printf("%lld",2*now);
for(i=4;i<=n;i++)printf(" %lld",2*(xm-xi+ym-yi));
}
}
ED
此题中输入数据的顺时针和无三点共线保证还没发现有什么具体作用,有想法的欢迎在下方讨论。