bzoj4232: [Neerc2011 Northern]Kids Like Cakes

时间:2023-03-09 02:51:30
bzoj4232: [Neerc2011 Northern]Kids Like Cakes

Description

给定一个n个点的严格凸多边形(各个内角<180°),现在要切出两个非退化三角形(三点不共线),要求两个三角形顶点必须是凸多边形的顶点,且三角形不可相交(但是点或边可以重合)。求两个三角形面积之差的最大值。

Input

第一行,一个整数N。
第二到N+1行,每行两个整数xi,yi,表示多边形的一个点,保证顶点按顺时针或逆时针顺序给出。

Output

输出答案,精确到小数点后1位。
最小三角形一定是相邻三点构成,因此只需枚举每个最小三角形,查询剩余部分中的最大三角形
dp,f[a][b]表示三角形一条边从a到b的,另一个顶点c在a到b之间的最大面积,固定a,令b递增则决策点c可以线性求出
辅助g[a][b]=max(g[a][b-1],g[a+1][b],f[a][b])可支持查询
#include<bits/stdc++.h>
typedef long long i64;
struct pos{int x,y;}ps[];
pos operator+(pos a,pos b){return (pos){a.x+b.x,a.y+b.y};}
pos operator-(pos a,pos b){return (pos){a.x-b.x,a.y-b.y};}
i64 operator*(pos a,pos b){return i64(a.x)*b.y-i64(a.y)*b.x;}
int n,ws[];
i64 ans=,s0[],ms[];
void maxs(i64&a,i64 b){if(a<b)a=b;}
int main(){
scanf("%d",&n);
for(int i=;i<=n;++i)scanf("%d%d",&ps[i].x,&ps[i].y);
if((ps[]-ps[])*(ps[]-ps[])<)std::reverse(ps+,ps+n+);
ps[n*+]=ps[];
ps[]=ps[n];
for(int i=;i<=n;++i)ps[n+i]=ps[i],ws[i]=i;
for(int d=;d<n;++d){
for(int l=,r=d;l<=n;++l,++r){
pos a=ps[r]-ps[l];
s0[l]=(ps[ws[l]]-ps[l])*a;
while(ws[l]+<r){
i64 s1=(ps[ws[l]+]-ps[l])*a;
if(s1<s0[l])break;
++ws[l];
s0[l]=s1;
}
maxs(ms[l],s0[l]);
}
ms[n+]=ms[];
for(int l=;l<=n;++l)maxs(ms[l],ms[l+]);
}
for(int l=,r=n-;l<=n;++l,++r)maxs(ans,ms[l]-(ps[r]-ps[l])*(ps[r+]-ps[l]));
printf("%lld.%lld\n",ans/,ans%*);
return ;
}