QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#124279#3139. Largest QuadrilateralGoatGirl98WA 1ms3140kbC++146.3kb2023-07-14 16:26:152023-07-14 16:26:15

Judging History

This is the latest submission verdict.

  • [2023-08-10 23:21:45]
  • System Update: QOJ starts to keep a history of the judgings of all the submissions.
  • [2023-07-14 16:26:15]
  • Judged
  • Verdict: WA
  • Time: 1ms
  • Memory: 3140kb
  • [2023-07-14 16:26:15]
  • Submitted

answer

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <functional>
#include <algorithm>
using namespace std;
const double INF = 1145141919810114514.0;
const double eps = 1e-9;
int sgn(double x)
{

    if(fabs(x) > eps)
        return x > 0 ? 1 : -1;
    else
        return 0;
}
struct point
{
    double x, y, idx;
    point(double _x = 0.0, double _y = 0.0) : x(_x), y(_y), idx(0) {}
    point operator-(const point& o) const { return point(x - o.x, y - o.y); }
    // cross product of vector 
    double operator^(const point& o) const { return x * o.y - y * o.x; }
    double dis2(const point& o) const { return (x - o.x) * (x - o.x) + (y - o.y) * (y - o.y); }
    double dis(const point& o) const { return sqrt(dis2(o)); }
    bool operator<(const point& o) const { return sgn(x - o.x) ? (sgn(x - o.x) < 0) : (sgn(y - o.y) < 0); }
    bool operator==(const point& o) const { return sgn(x - o.x) == 0 && sgn(y - o.y) == 0; }
};
struct line
{
    point s, e;
    line() {}
    line(point _s, point _e) : s(_s), e(_e) {}
    // segment only
    double len() const { return s.dis(e); }
    double dis_point_to_line(const point& p) const { return fabs((p - s) ^ (e - s)) / len(); }
};
// andrew
vector<point> get_convex(vector<point>& points)
{
    int n = (int)points.size();
    // sorted before calling this
    // sort(points.begin(), points.end());
    vector<int> stk;
    vector<bool> used(n);
    stk.push_back(0);
    // upper convex
    for (int i = 1; i < n; ++i)
    {
        while (stk.size() >= 2 && sgn((points[stk[stk.size() - 1]] - points[stk[stk.size() - 2]]) ^ (points[i] - points[stk[stk.size() - 1]])) <= 0)
            used[stk.back()] = false, stk.pop_back();
        used[i] = true, stk.push_back(i);
    }
    // stk.back() == n - 1
    // lower convex
    int upper_size = stk.size();
    for (int i = n - 2; i >= 0; --i)
    {
        if (used[i])
            continue;
        while (stk.size() > upper_size && sgn((points[stk[stk.size() - 1]] - points[stk[stk.size() - 2]]) ^ (points[i] - points[stk[stk.size() - 1]])) <= 0)
            used[stk.back()] = false, stk.pop_back();
        used[i] = true, stk.push_back(i);
    }
    // stk.back() == stk[0]
    vector<point> ret;
    for (int i = 0; i < stk.size(); ++i)
        ret.push_back(points[stk[i]]);
    return ret;
}
double largest_quadrilateral(vector<point>& points)
{
    // int n = points.size();
    sort(points.begin(), points.end());
    points.erase(unique(points.begin(), points.end()), points.end());
    int n = points.size();
    for (int i = 0; i < n; ++i)
        points[i].idx = i;
    vector<point> hull = get_convex(points);
    int m = hull.size() - 1;
    if (m == 2) // collinear points
        return 0.0;
    else if (m == 3) // big triangle(hull) - small triangle(inside)
    {
        double triangle_area_double = fabs((hull[2] - hull[1]) ^ (hull[1] - hull[0]));
        double cut_triangle_double = INF;
        for (int i = 0; i < n; ++i)
        {
            if (points[i].idx == hull[0].idx || points[i].idx == hull[1].idx || points[i].idx == hull[2].idx)
                continue;
            double cut_double_1 = fabs((hull[0] - points[i]) ^ (hull[1] - points[i]));
            double cut_double_2 = fabs((hull[1] - points[i]) ^ (hull[2] - points[i]));
            double cut_double_3 = fabs((hull[2] - points[i]) ^ (hull[0] - points[i]));
            cut_triangle_double = min(min(cut_triangle_double, cut_double_1), min(cut_double_2, cut_double_3));
        }
        if (sgn(INF - cut_triangle_double) == 0)
            return 0.0;
        else
            return (triangle_area_double - cut_triangle_double) / 2.0;
    }
    else // rotating cliper (2 groups)
    {
        double ans_double = 0.0;
        // Antipodal point-point (i, j) and (x, y)
        int i = 0, j = 1, x = 0, y = 1;
        for (; i < m; ++i)
        {
            while (1)
            {
                int flag = sgn((hull[(i + 1) % m] - hull[i]) ^ (hull[(j + 1) % m] - hull[j]));
                if (flag <= 0) // (i, j) is antipodal point-point
                {
                    line diagonal = line(hull[i], hull[j]);
                    while ((x + 1) % m != j && sgn(diagonal.dis_point_to_line(hull[x]) - diagonal.dis_point_to_line(hull[(x + 1) % m])) <= 0)
                        x = (x + 1) % m;
                    while ((y + 1) % m != i && sgn(diagonal.dis_point_to_line(hull[y]) - diagonal.dis_point_to_line(hull[(y + 1) % m])) <= 0)
                        y = (y + 1) % m;
                    ans_double = max(ans_double, diagonal.len() * (diagonal.dis_point_to_line(hull[x]) + diagonal.dis_point_to_line(hull[y])));
                    
                    // corner case : (i, (i + 1) % m) parallel with (j, (j + 1) % m)
                    if (flag == 0)
                    {
                        j = (j + 1) % m;
                        diagonal = line(hull[i], hull[j]);
                        while ((x + 1) % m != j && sgn(diagonal.dis_point_to_line(hull[x]) - diagonal.dis_point_to_line(hull[(x + 1) % m])) <= 0)
                            x = (x + 1) % m;
                        while ((y + 1) % m != i && sgn(diagonal.dis_point_to_line(hull[y]) - diagonal.dis_point_to_line(hull[(y + 1) % m])) <= 0)
                            y = (y + 1) % m;
                        ans_double = max(ans_double, diagonal.len() * (diagonal.dis_point_to_line(hull[x]) + diagonal.dis_point_to_line(hull[y])));
                        j = (j + m - 1) % m;
                    }
                    break;
                }
                // rad : i < x < j < y
                if (y == j)
                    y = (y + 1) % m;
                j = (j + 1) % m;
            }
            if (x == i)
                x = (x + 1) % m;
        }
        return ans_double / 2.0;
    }
}
int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        int n;
        scanf("%d", &n);
        vector<point> points(n);
        for (int i = 0; i < n; ++i)
            scanf("%lf%lf", &points[i].x, &points[i].y);
        double ans = largest_quadrilateral(points);
        if (sgn(ans - (long long)(ans + eps)) == 0)
            printf("%lld\n", (long long)(ans + eps));
        else
            printf("%lld.5\n", (long long)(ans + eps));
    }
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 1ms
memory: 3140kb

input:

3
5
0 0
1 0
3 1
1 2
0 1
4
0 0
4 0
0 4
1 1
4
0 0
1 1
2 2
1 1

output:

3
6
0

result:

ok 3 lines

Test #2:

score: 0
Accepted
time: 1ms
memory: 3124kb

input:

1
4
0 0
1 0
0 1
3 2

output:

2.5

result:

ok single line: '2.5'

Test #3:

score: 0
Accepted
time: 1ms
memory: 3016kb

input:

3
4
0 0
0 0
0 0
0 0
5
0 0
1 0
3 1
1 2
0 1
4
0 0
4 0
0 4
1 1

output:

0
3
6

result:

ok 3 lines

Test #4:

score: -100
Wrong Answer
time: 1ms
memory: 3068kb

input:

3
4
0 0
1 1
2 2
1 1
5
0 0
3 3
1 1
4 4
2 2
6
0 0
0 4
4 0
0 0
1 1
1 2

output:

0
0
6

result:

wrong answer 3rd lines differ - expected: '8', found: '6'