QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#106261 | #4226. Cookie Cutter | walnutwaldo20# | TL | 2ms | 3844kb | C++11 | 8.9kb | 2023-05-17 04:41:52 | 2023-05-17 04:41:53 |
Judging History
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...