如果你WA#3#5#6#8
查看原帖
如果你WA#3#5#6#8
1022761
wuuk楼主2024/1/23 18:54

把O2优化关了就AC了

我也不知道具体啥问题

以下是我的代码

#include <bits/stdc++.h>
using namespace std;
#define MAXN 50005
typedef long long ll;
struct Point
{
    ll x, y;
    Point(ll _x = 0, ll _y = 0)
    {
        x = _x, y = _y;
    }
    Point operator-(Point const &next) const
    {
        Point res(x - next.x, y - next.y);
        return res;
    }
    ll operator*(Point const &next) const
    {
        return x * next.y - y * next.x;
    }
    bool operator==(Point const &next) const
    {
        return x == next.x && y == next.y;
    }
}p[MAXN], h[MAXN]; // p存储点或向量
int stk[MAXN]; // stk存的是下标,用数组实现栈
bool used[MAXN]; // used[i]表示下标i对应的点在不在凸包上
int tp, n, ans;

ll dis(Point a, Point b)
{
    ll dx = (a.x - b.x) * (a.x - b.x);
    ll dy = (a.y - b.y) * (a.y - b.y);
    return dx + dy;
}
double sumdis()
{
    double res = 0;
    for (int i = 1; i <= ans; i++)
    {
        res += dis(h[i], h[i + 1]);
    }
    return res;
}
bool cmp1(Point const &mext, Point const &next)
{
	return (mext.x < next.x) || (mext.x == next.x && mext.y < next.y); 
}
// Andrew算法
void Andrew()
{
    tp = 0; // 初始化栈
    memset(used, 0, sizeof(used));
    memset(stk, 0, sizeof(stk));
    sort(p + 1, p + 1 + n, cmp1);
    stk[++tp] = 1;
    for (int i = 2; i <= n; i++)
    {
        //下凸包顺序遍历,有右转就右转
        while (tp >= 2 && (p[stk[tp]] - p[stk[tp-1]]) * (p[i] - p[stk[tp]]) <= 0)
            used[stk[tp--]] = 0; // 弹出栈顶
        used[i] = 1; // 记录新点
        stk[++tp] = i; // 新点入栈
    }
    int tmp = tp; // tmp表示下凸包大小
    for (int i = n - 1; i > 0; i--)
    {
        // 上凸包逆序遍历,有右转就右转
        if (!used[i])
        {
            while (tp > tmp && (p[stk[tp]] - p[stk[tp-1]]) * (p[i] - p[stk[tp]]) <= 0)
                used[stk[tp--]] = 0;
            used[i] = 1;
            stk[++tp] = i;
        }
    }
    for (int i = 1; i <= tp; i++)
    {
        h[i] = p[stk[i]]; // h以1号点开始,以1号点结束
    }
    ans = tp - 1; // ans表示凸包的点的实际数量
}
/*
 * 旋转卡壳法(旋转卡尺)
 * 枚举凸包的边,同时维护其他需要的点
 * 可求解凸包直径,最小矩形覆盖,最大面积等
 * 
 * 根据我们枚举的边,可以从每个维护的点画出一条或平行或垂直的直线,
 * 为了确保对于当前枚举的边的最优性,我们的任务就是使这些直线能将
 * 凸包正好卡住。而边通常是按照向某一方向旋转的顺序来枚举,所以整
 * 个过程就是在边「旋转」,边「卡壳」。
*/
ll square(Point a, Point b, Point c)
{
    // 三角形面积
    return abs((c - a) * (b - a));
}
ll get_longest()
{
    ll res;
    int j = 3;
    if (ans <= 1) return 0;
    if (ans == 2) return dis(h[1], h[2]);
    // 枚举边h[i]h[i+1]
    for (int i = 1; i <= ans; i++)
    {
        if (h[i] == h[i+1]) continue;
        while (square(h[i], h[i+1], h[j]) <= square(h[i], h[i+1], h[j%ans+1]))
            j = j % tp + 1;
        res = max({res, dis(h[i], h[j]), dis(h[i+1], h[j])});
    }
    return res;
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> p[i].x >> p[i].y;
    }
    Andrew();
    cout << get_longest() << endl;
}
2024/1/23 18:54
加载中...