2019-2020 ICPC Asia Taipei-Hsinchu Regional Contest
L
题意:给N个点(N
≤
\le
≤ 4096),求四边形最大面积(只要有四个点即可,可以退化成三角形或直线,注意重复点的情况)
题解:建凸包,旋转卡壳跑每个点的对踵点。对于一对对踵点<u, v>,枚举其他点,找出直线<u, v>两侧面积最大、最小值。如果两侧都有点,用两侧的最大值相加更新答案;否则用有点的那一侧的最大值减最小值更新答案。
O(N2)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
const int N=5010;
const LL inf=2e18;
struct NODE{
LL x,y;
NODE(){}
NODE (LL a,LL b){ x=a; y=b; }
NODE friend operator - (NODE a,NODE b)
{ return NODE(a.x-b.x,a.y-b.y); }
}node[N];
int que[N];
int stop,n;
LL X(NODE a,NODE b)
{
return a.x*b.y-a.y*b.x;
}
LL dist(NODE a,NODE b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
int cmp(NODE a,NODE b)
{
NODE x=a-node[1];
NODE y=b-node[1];
LL s=X(x,y);
return s>0||(s==0&&dist(node[1],a)<=dist(node[1],b));
}
LL S(int a,int b,int c)
{
NODE x=node[b]-node[a];
NODE y=node[c]-node[a];
return X(x,y);
}
LL cal(int a,int b)
{
LL mx1,mx2,mn1,mn2;
mx1=mx2=-1;
mn1=mn2=inf;
for(int i=1;i<=n;i++)
if(i!=a&&i!=b)
{
LL s=S(a,b,i);
if(s>0)
mx1=max(mx1,s),mn1=min(mn1,s);
else
mx2=max(mx2,-s),mn2=min(mn2,-s);
}
if(mx1==-1)
return mx2-mn2;
if(mx2==-1)
return mx1-mn1;
return mx1+mx2;
}
int main()
{
int T;
scanf("%d",&T);
while(T)
{
T--;
LL ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
cin>>node[i].x>>node[i].y;
int k=1;
for(int i=1;i<=n;i++)
if(node[i].y<node[k].y||(node[i].y==node[k].y&&node[i].x<node[k].x))
k=i;
swap(node[k].x,node[1].x); swap(node[k].y,node[1].y);
sort(node+2,node+n+1,cmp);
que[0]=1; que[1]=2;
stop=1;
for(int i=3;i<=n;i++)
{
while(stop>=1&&S(que[stop-1],que[stop],i)<=0)
stop--;
que[++stop]=i;
}
if(stop<=1)
{
printf("0\n");
continue;
}
int j=1;
for(int i=0;i<stop;i++)
{
while(abs(S(que[i],que[(i+1)%stop],que[j%stop]))<abs(S(que[i],que[(i+1)%stop],que[(j+1)%stop])))
j++;
ans=max(ans,cal(que[i],que[j%stop]));
}
if(ans&1)
cout<<ans/2<<".5"<<endl;
else
cout<<ans/2<<endl;
}
return 0;
}