题目链接
一、题目
个点坐标分别是
,坐标都是整数。
选择个点作为四边形的顶点,求最大四边形面积。
多组测例。
数据范围:
二、题解
直接上......
这题时限 竟然卡
的做法我是不理解的。
的做法就是枚举对角线然后三分两侧的点,但是过不去,竟然卡这个常数。
接着优化,考虑,那就是旋转卡壳了。
先求一下凸包,然后分类讨论。
(1)凸包上只有两个点,答案是
(2)凸包上只有三个点,那么答案应该是最大的凹四边形的面积,那么枚举凸包内部点,用凸包的三角形减去这些内部点作为顶点的三角形面积,取最大值,具体看代码吧。
(3)凸包上的点多于三个,那么答案显然是凸包上的四个点,那么凸包内部点就不考虑了。枚举对角线,假设对角线的端点是,另外两个端点是
,并且
在对角线的两侧。
因为凸包有单峰性,所以在 固定时
扫一遍就行了,复杂度稳定
。
因为坐标是整数,所以答案是整数或者小数部分是,所以可以用
运算,减小常数。
三、代码
#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x) (int)x.size()
#define cl(x) x.clear()
#define all(x) x.begin() , x.end()
#define rep(i , x , n) for(int i = x ; i <= n ; i ++)
#define per(i , n , x) for(int i = n ; i >= x ; i --)
#define mem0(x) memset(x , 0 , sizeof(x))
#define mem_1(x) memset(x , -1 , sizeof(x))
#define mem_inf(x) memset(x , 0x3f , sizeof(x))
#define debug(x) cerr << #x << " = " << x << '\n'
#define ddebug(x , y) cerr << #x << " = " << x << " " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ;
mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count()) ;
int n ;
struct point
{
ll x , y ;
bool operator < (const point &s) const
{
if(x != s.x) return x < s.x ;
else return y < s.y ;
}
} p[maxn] ;
ll multi(point p0 , point p1 , point p2)
{
ll x1 , y1 , x2 , y2 ;
x1 = p1.x - p0.x , y1 = p1.y - p0.y ;
x2 = p2.x - p0.x , y2 = p2.y - p0.y ;
return x1 * y2 - x2 * y1 ;
}
ll area(point p0 , point p1 , point p2)
{
ll sum = 0 ;
sum += multi((point){0 , 0} , p0 , p1) ;
sum += multi((point){0 , 0} , p1 , p2) ;
sum += multi((point){0 , 0} , p2 , p0) ;
return abs(sum) ;
}
struct Convex_hull
{
int cnt , sta[maxn] ;
void init()
{
cnt = 0 ;
}
void solve() //注意左下角的点存储了两次 分别是数组中的第一个点和最后一个点
{
sort(p + 1 , p + n + 1) ;
sta[++ cnt] = 1 ;
rep(i , 2 , n)
{
//假如想让凸包的边上有多个点,那就把 <= 改成 <
while(cnt >= 2 && multi(p[sta[cnt - 1]] , p[sta[cnt]] , p[i]) <= 0)
cnt -- ;
sta[++ cnt] = i ;
}
int temp = cnt ;
per(i , n - 1 , 1)
{
while(cnt > temp && multi(p[sta[cnt - 1]] , p[sta[cnt]] , p[i]) <= 0)
cnt -- ;
sta[++ cnt] = i ;
}
rep(i , 1 , cnt - 1) sta[i + (cnt - 1)] = sta[i] ;
}
void cal()
{
int siz = cnt - 1 ;
ll ans = 0 ;
if(siz == 2) cout << "0\n" ;
else if(siz == 3)
{
rep(i , 1 , n)
if(i != sta[1] && i != sta[2] && i != sta[3])
{
ans = max(ans , area(p[sta[1]] , p[sta[2]] , p[sta[3]]) - area(p[sta[1]] , p[sta[2]] , p[i])) ;
ans = max(ans , area(p[sta[1]] , p[sta[2]] , p[sta[3]]) - area(p[sta[2]] , p[sta[3]] , p[i])) ;
ans = max(ans , area(p[sta[1]] , p[sta[2]] , p[sta[3]]) - area(p[sta[1]] , p[sta[3]] , p[i])) ;
}
if(ans % 2 == 1) cout << ans / 2 << ".5\n" ;
else cout << ans / 2 << '\n' ;
}
else
{
rep(i , 1 , siz)
{
int l = i + 1 , r = i + 3 ;
rep(j , i + 2 , siz)
{
while(l + 1 < j && area(p[sta[i]] , p[sta[j]] , p[sta[l + 1]]) > area(p[sta[i]] , p[sta[j]] , p[sta[l]])) l ++ ;
while(r + 1 < siz + i && area(p[sta[i]] , p[sta[j]] , p[sta[r + 1]]) > area(p[sta[i]] , p[sta[j]] , p[sta[r]])) r ++ ;
ans = max(ans , area(p[sta[i]] , p[sta[j]] , p[sta[l]]) + area(p[sta[i]] , p[sta[j]] , p[sta[r]])) ;
}
}
if(ans % 2 == 1) cout << ans / 2 << ".5\n" ;
else cout << ans / 2 << '\n' ;
}
}
} convex_hull ;
int main()
{
ios ;
int t ;
cin >> t ;
while(t --)
{
cin >> n ;
rep(i , 1 , n) cin >> p[i].x >> p[i].y ;
convex_hull.init() ;
convex_hull.solve() ;
convex_hull.cal() ;
}
return 0 ;
}