QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#106261#4226. Cookie Cutterwalnutwaldo20#TL 2ms3844kbC++118.9kb2023-05-17 04:41:522023-05-17 04:41:53

Judging History

你现在查看的是最新测评结果

  • [2023-08-10 23:21:45]
  • System Update: QOJ starts to keep a history of the judgings of all the submissions.
  • [2023-05-17 04:41:53]
  • 评测
  • 测评结果:TL
  • 用时:2ms
  • 内存:3844kb
  • [2023-05-17 04:41:52]
  • 提交

answer

#include <iostream>
#include <vector>
#include <complex>
#include <algorithm>
#include <iomanip>

#define F0R(i, a) for (int i = 0; i < (a); i++)

#define PB push_back
#define MP make_pair

#define F first
#define S second
#define X real()
#define Y imag()

#define SQ(x) ((x) * (x))

#define MAXM 3000
#define all(x) (x).begin(), (x).end()

using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef complex<ll> cll;
typedef complex<ld> cld;
typedef vector<int> vi;

typedef struct dir_data { // Represent a line (swinging counter-clockwise)
    cll vec; // ray in the direction that is being removed
    vector<int> to_add; // points being added as they enter the region
    vector<int> to_remove; // points being removed as they exit the region
} dir_data;

ll n;
int m;
vector<cll> points;
vector<dir_data> rot_data[MAXM];

ll crossp(cll a, cll b) {
    return a.X * b.Y - a.Y * b.X;
}

ld crossp(cld a, cld b) {
    return a.X * b.Y - a.Y * b.X;
}

ll dotp(cll a, cll b) {
    return a.X * b.X + a.Y * b.Y;
}

ld dotp(cld a, cld b) {
    return a.X * b.X + a.Y * b.Y;
}

ll sqdis(cll a, cll b) {
    cll vec = a - b;
    return SQ(vec.X) + SQ(vec.Y);
}

ll gcd(ll a, ll b) {
    if (a < 0 || b < 0) return gcd(abs(a), abs(b));
    if (a < b) return gcd(b, a);
    if (b == 0) return a;
    return gcd(b, a % b);
}

cll normalize(cll pnt) {
    ll g = gcd(pnt.X, pnt.Y);
    return cll(pnt.X / g, pnt.Y / g);
}

cll get_angle(cll center, cll point) {
    return normalize(point - center);
}

int getQuad(cll vec) {
    if (vec.X > 0 && vec.Y >= 0) return 1;
    else if (vec.X <= 0 && vec.Y > 0) return 2;
    else if (vec.X < 0 && vec.Y <= 0) return 3;
    else return 4;
}

bool cmpVec(cll vecA, cll vecB) {
    int quadA = getQuad(vecA);
    int quadB = getQuad(vecB);
    if (quadA != quadB) return quadA < quadB;
    return crossp(vecA, vecB) > 0;
}

void build_data(int node) {
    vector<pair<cll, pii>> to_sort;
    cll center = points[node];

    F0R(i, m) if (i != node) {
        to_sort.PB(MP(get_angle(center, points[i]), MP(i, -1))); // -1 = remove
        to_sort.PB(MP(-get_angle(center, points[i]), MP(i, 1))); // 1 = add
    }
    to_sort.PB(MP(cll(0, 1), MP(-1, 0)));
    to_sort.PB(MP(cll(0, -1), MP(-1, 0)));
    to_sort.PB(MP(cll(1, 0), MP(-1, 0)));
    to_sort.PB(MP(cll(-1, 0), MP(-1, 0)));
    to_sort.PB(MP(get_angle(center, cll(n, n)), MP(-1, 0)));
    to_sort.PB(MP(-get_angle(center, cll(n, n)), MP(-1, 0)));
    to_sort.PB(MP(get_angle(center, cll(0, n)), MP(-1, 0)));
    to_sort.PB(MP(-get_angle(center, cll(0, n)), MP(-1, 0)));
    to_sort.PB(MP(get_angle(center, cll(0, 0)), MP(-1, 0)));
    to_sort.PB(MP(-get_angle(center, cll(0, 0)), MP(-1, 0)));
    to_sort.PB(MP(get_angle(center, cll(n, 0)), MP(-1, 0)));
    to_sort.PB(MP(-get_angle(center, cll(n, 0)), MP(-1, 0)));

    sort(to_sort.begin(), to_sort.end(), [](pair<cll, pii> a, pair<cll, pii> b) -> bool {
        cll veca = a.F;
        cll vecb = b.F;
        return cmpVec(veca, vecb);
    });

    vector<dir_data> v;
    dir_data curr_data = {
        .vec=cll(0, 0),
        .to_add=vi(),
        .to_remove=vi()
    };

    for (const pair<cll, pii> item : to_sort) {
        if (item.F != curr_data.vec) {
            if (curr_data.vec != cll(0, 0)) {
                // Sort from closest_to_farthest
                sort(curr_data.to_remove.begin(), curr_data.to_remove.end(), [center](int a, int b) -> bool {
                    cll pointA = points[a];
                    cll pointB = points[b];
                    return sqdis(center, pointA) < sqdis(center, pointB);
                });
                sort(curr_data.to_add.begin(), curr_data.to_add.end(), [center](int a, int b) -> bool {
                    cll pointA = points[a];
                    cll pointB = points[b];
                    return sqdis(center, pointA) < sqdis(center, pointB);
                });

                v.PB(curr_data);
            }
            curr_data = {
                .vec=item.F,
                .to_add=vi(),
                .to_remove=vi()
            };
        }
        if (item.S.S == 1) {
            curr_data.to_add.PB(item.S.F);
        } else if (item.S.S == -1) {
            curr_data.to_remove.PB(item.S.F);
        } else {
            // To ignore  
        }
    }

    rot_data[node] = v;
}

void update_res(ld& res, ld area, int cnt) {
    res = max(res, (ld)cnt / m - area / (n * n));
}

vector<pair<cld, cld>> walls;

pair<int, cld> lineInter(cld s1, cld e1, cld s2, cld e2) {
    auto d = crossp(e1 - s1, e2 - s2);
    if (d == 0) return { -(crossp(e1 - s1, s2 - s1) == 0), cld(0, 0) };
    auto p = crossp(e1 - s2, e2 - s2), q = crossp(e2 - s2, s1 - s2);
    return {1, (s1 * p + e1 * q) / d};
}

bool onSegment(cld pnt, cld endp1, cld endp2) {
    return crossp(endp1 - pnt, endp2 - pnt) == 0 && dotp(endp1 - pnt, endp2 - pnt) <= 0;
}

cld to_wall(cll _center, cll _vec1) {
    cld center = cld(_center.X, _center.Y);
    cld vec1 = cld(_vec1.X, _vec1.Y);

    vec1 *= n;
    for (const pair<cld, cld> wall: walls) {
        cld endp1 = wall.F;
        cld endp2 = wall.S;

        pair<int, cld> inter = lineInter(endp1, endp2, center, center + vec1);
        if (inter.F == 1) {
            cld pnt = inter.S;
            if (onSegment(pnt, endp1, endp2) && dotp(pnt - center, vec1) >= 0) return pnt - center;
        }
    }
    return cld(0, 0); // shouldn't happen
}

ld darea(cll center, cll vec, cll vec2) {
    cld fullvec1 = to_wall(center, vec);
    cld fullvec2 = to_wall(center, vec2);

    cld revvec1 = to_wall(center, -vec);
    cld revvec2 = to_wall(center, -vec2);

    // cout << "ToRemove: " << fullvec1 << " -> " << fullvec2 << " ToAdd: " << revvec1 << " -> " << revvec2 << endl;

    return (abs(crossp(revvec1, revvec2)) - abs(crossp(fullvec1, fullvec2))) / 2;
}

void update(ld& res, int i, int cnt) {
    int pivot = i;
    cll dir = cll(1, 0);
    ld area = n * (n - points[i].Y);

    while(true) {
        // cout << "Cnt: " << cnt << " " << points[pivot] << " : " << dir << " : " << area << endl;

        update_res(res, area, cnt);

        auto ptr = upper_bound(
            all(rot_data[pivot]),
            (dir_data) {.vec=dir, .to_add = vi(), .to_remove = vi()},
            [](dir_data da, dir_data db) -> bool {
                cll v1 = da.vec;
                cll v2 = db.vec;
                return cmpVec(v1, v2);
            }
        );
        if (ptr == rot_data[pivot].end()) break;

        area += darea(points[pivot], dir, ptr->vec);
        vi to_rem = ptr->to_remove;
        vi to_add = ptr->to_add;
        while (!to_rem.empty() && !to_add.empty()) {
            to_rem.pop_back();
            to_add.pop_back();
        }
        if (!to_rem.empty()) pivot = to_rem.back();
        else if (!to_add.empty()) pivot = to_add.back();
        else pivot = pivot;
        dir = ptr->vec;
    };
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> n >> m;
    F0R(i, m) {
        ll x, y;
        cin >> x >> y;
        points.PB(cll(x, y));
    }

    walls.PB(MP(cld(0, 0), cld(n, 0)));
    walls.PB(MP(cld(n, 0), cld(n, n)));
    walls.PB(MP(cld(n, n), cld(0, n)));
    walls.PB(MP(cld(0, n), cld(0, 0)));

    F0R(i, m) build_data(i);

    // F0R(i, m) {
    //     cout << points[i] << endl;
    //     cout << "Goes through:";
    //     for (const dir_data dd : rot_data[i]) {
    //         cout << " (";
    //         for (const int to_add: dd.to_add) {
    //             cout << "+" << points[to_add] << ", ";
    //         }
    //         for (const int to_remove: dd.to_remove) {
    //             cout << "-" << points[to_remove] << ", ";
    //         }
    //         cout << ")";
    //     }
    //     cout << endl;
    // }

    vi sorted_points = vi();
    F0R(i, m) sorted_points.PB(i);
    sort(all(sorted_points), [](int ai, int bi) -> bool {
        cll a = points[ai];
        cll b = points[bi];
        if (a.Y != b.Y) return a.Y > b.Y; // We want top first
        return a.X < b.X; // We want left first
    });

    ld res = 0;

    F0R(cntm1, m) {
        int cnt = cntm1 + 1;
        int idx = sorted_points[cntm1];

        update(res, idx, cnt);

        // cout << points[idx] << endl;
        // cout << "Goes through:";
        // for (const dir_data dd : rot_data[idx]) {
        //     cout << " (";
        //     for (const int to_add: dd.to_add) {
        //         cout << "+" << points[to_add] << ", ";
        //     }
        //     for (const int to_remove: dd.to_remove) {
        //         cout << "-" << points[to_remove] << ", ";
        //     }
        //     cout << ")";
        // }
        // cout << endl;
    }

    cout << fixed << setprecision(12) << res << endl;

    return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 2ms
memory: 3844kb

input:

5 8
1 1
1 2
1 3
2 1
3 1
3 4
4 1
4 2

output:

0.375000000000

result:

ok found '0.3750000', expected '0.3750000', error '0.0000000'

Test #2:

score: -100
Time Limit Exceeded

input:

10000 2916
93 93
93 278
93 463
93 649
93 834
93 1019
93 1204
93 1389
93 1574
93 1760
93 1945
93 2130
93 2315
93 2500
93 2685
93 2871
93 3056
93 3241
93 3426
93 3611
93 3796
93 3982
93 4167
93 4352
93 4537
93 4722
93 4907
93 5093
93 5278
93 5463
93 5648
93 5833
93 6018
93 6204
93 6389
93 6574
93 6759...

output:


result: