atcoder.jp/contests/ab…
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
struct P{
ll px,py;
};
// 向量加法
P operator+(const P& a1, const P& a2) {
return P{ a1.px + a2.px, a1.py + a2.py };
}
// 向量减法
P operator-(const P& a1, const P& a2) {
return { a1.px - a2.px, a1.py - a2.py };
}
bool operator<(const P& a1, const P& a2) {
if (a1.px < a2.px) return true;
if (a1.px > a2.px) return false;
if (a1.py < a2.py) return true;
return false;
}long long crs(P p1, P p2) {
return p1.px * p2.py - p1.py * p2.px;
}
int main(){
int n;cin>>n;
vector<P>pts(n);
for(int i=0;i<n;i++){cin>>pts[i].px>>pts[i].py;
}ll s=0;
for(int i=2;i<n;i++){
s+=abs(crs(pts[i-1]-pts[0],pts[i]-pts[0]));
}ll res=8e18;
ll e=0;
int q=1;
for(int p=0;p<n;p++){
while(4*e<s){
e+=abs(crs(pts[q]-pts[p],pts[(q+1)%n]-pts[p]));
q=(q+1)%n;
res=min(res,abs(4*e-s));
}e-=abs(crs(pts[p]-pts[q],pts[(p+1)%n]-pts[q]));
res=min(res,abs(4*e-s));}
cout<<res;}
1. 对象是凸多边形(点按顺序排列)
2. 固定一个端点 p,另一个端点 q 往右移
3. 面积随 q 右移单调递增(只增不减)
4. 我们要找面积最接近某个目标值(S/4)
满足单调性 → 双指针不会回退 → 滑动窗口成立。
atcoder.jp/contests/ty…
找几个点的最大角
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
// 点结构体,存储坐标
struct Point {
double px, py;
};
// 向量减法:a1 - a2
Point operator-(const Point& a1, const Point& a2) {
return Point{ a1.px - a2.px, a1.py - a2.py };
}
// 计算向量 G 的极角(返回角度 0~360 度)
double getangle(Point G) {
// 向量在 x 轴上方(y ≥ 0)
if (G.py >= 0.0) {
double len = sqrt(G.px * G.px + G.py * G.py);
double cos_val = G.px / len;
// acos 算出弧度 → 转角度
double angle = acos(cos_val) * 180.0 / acos(-1.0);
return angle;
}
// 向量在 x 轴下方(y < 0)
else {
double len = sqrt(G.px * G.px + G.py * G.py);
double cos_val = G.px / len;
double angle = acos(cos_val) * 180.0 / acos(-1.0);
// 下方角度 = 360 - 上半平面角度
return 360.0 - angle;
}
}
// 计算两个极角 a1、a2 之间形成的最小夹角(0~180 度)
double getangle2(double a1, double a2) {
double diff = abs(a1 - a2);
// 取 <= 180° 的那个角
if (diff >= 180.0) return 360.0 - diff;
return diff;
}
int N;
Point G[2009]; // 存储所有点
// 以第 pos 个点为顶点,计算最大角
double solve(int pos) {
// 把所有其他点相对于 pos 点的极角存起来
vector<double> angles;
for (int i = 1; i <= N; i++) {
if (i == pos) continue;
Point vec = G[i] - G[pos];
double ang = getangle(vec);
angles.push_back(ang);
}
// 极角排序(关键优化)
sort(angles.begin(), angles.end());
double max_angle = 0.0;
// 对每个点 A,找与它夹角最接近 180° 的点 C
for (int i = 0; i < angles.size(); i++) {
// 目标角度 = 当前角度 + 180°
double target = angles[i] + 180.0;
if (target >= 360.0) target -= 360.0;
// 二分查找最接近 target 的位置
int pos1 = lower_bound(angles.begin(), angles.end(), target) - angles.begin();
// 候选点:找到的点、前一个点(最接近180°)
int c1 = pos1 % angles.size();
int c2 = (pos1 - 1 + angles.size()) % angles.size();
double ang1 = getangle2(angles[i], angles[c1]);
double ang2 = getangle2(angles[i], angles[c2]);
max_angle = max({ max_angle, ang1, ang2 });
}
return max_angle;
}
// 暴力 O(N^3) 解法(仅用来理解,N=2000 会超时)
double solve_Slow() {
double ans = 0.0;
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
for (int k = 1; k <= N; k++) {
if (i == j || i == k || j == k) continue;
double a1 = getangle(G[i] - G[j]);
double a2 = getangle(G[k] - G[j]);
ans = max(ans, getangle2(a1, a2));
}
}
}
return ans;
}
// 正解 O(N^2 log N) 算法
double solve_Fast() {
double ans = 0.0;
// 枚举每个点作为角的顶点
for (int i = 1; i <= N; i++) {
double current_max = solve(i);
ans = max(ans, current_max);
}
return ans;
}
int main() {
// 输入
cin >> N;
for (int i = 1; i <= N; i++) {
cin >> G[i].px >> G[i].py;
}
// 计算答案
double ans = solve_Fast();
// 输出 12 位小数
printf("%.12lf\n", ans);
return 0;
}