【LOJ2329】「清華集訓 2017」我的生命已如風中殘燭
阿新 • • 發佈:2018-11-08
【題目連結】
【思路要點】
- 一個直觀的思路是模擬該過程,當路上遇到環的時候通過類似取模的手段加速。
- 注意到每繞一個環 的長度至少減半,因此繞環的個數不會超過 。並且一個點如果在某一時刻不能夠到,那麼這個點就不會再被夠到,所以找到一個環至多需要遍歷 個點,因此如果我們預處理每個點作為原點時極角排序的結果,這個做法單組資料的時間複雜度為 ,可以用 表優化至 ,應該已經能夠通過本題。
- 進一步考慮,每一個環都是一個凸包,假設當前點為 ,其在凸包上的前驅為 ,我們直接暴力找 的後繼 會掃描射線 和射線 的夾角內的所有點,而每個點至多屬於 個這樣的區域,因此暴力找到一個環的時間複雜度就是 。這個做法單組資料的時間複雜度為
- 時間複雜度 。
【程式碼】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e3 + 5; const double pi = acos(-1); const double eps = 1e-8; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct point {int x, y; }; point operator + (point a, point b) {return (point) {a.x + b.x, a.y + b.y}; } point operator - (point a, point b) {return (point) {a.x - b.x, a.y - b.y}; } point operator * (point a, int b) {return (point) {a.x * b, a.y * b}; } ll operator * (point a, point b) {return 1ll * a.x * b.y - 1ll * a.y * b.x; } double dist(point a) {return sqrt(1ll * a.x * a.x + 1ll * a.y * a.y); } double PolarAngle(point a) {return atan2(a.y, a.x); } struct info {int pos; double dist, alpha; }; bool cmp(info a, info b) { if (fabs(a.alpha - b.alpha) <= eps) return a.dist < b.dist; else return a.alpha < b.alpha; } int n, m, home[MAXN][MAXN]; point s, t; double l; info a[MAXN][MAXN]; point p[MAXN]; int work(int pos, int from, double len) { if (from == n + 1) { double tmp = PolarAngle(p[pos] - s) + 4 * pi; for (int i = 1; i <= 3 * n - 3; i++) if (a[pos][i].alpha < tmp - eps && a[pos][i].dist < len) return 1 + work(a[pos][i].pos, pos, len - a[pos][i].dist); return 0; } else { int ans = 0, tot = 0; static int path[MAXN], vis[MAXN]; memset(vis, 0, sizeof(vis)); path[++tot] = pos; while (vis[pos] == 0) { vis[pos] = tot; int nxt = 0; for (int i = home[pos][from]; i <= 3 * n - 3; i++) if (a[pos][i].dist < len) { ans++; nxt = a[pos][i].pos; len -= a[pos][i].dist; break; } if (nxt == 0) return ans; else { from = pos; pos = nxt; } path[++tot] = pos; } int start = vis[pos]; for (int i = start; i < tot; i++) { int nxt = 0; for (int i = home[pos][from]; i <= 3 * n - 3; i++) if (a[pos][i].dist < len) { ans++; nxt = a[pos][i].pos; len -= a[pos][i].dist; break; } if (nxt == 0) return ans; else { from = pos; pos = nxt; if (pos != path[i + 1]) return ans + work(pos, from, len); } } double c = 0; for (int i = start; i < tot; i++) c += dist(p[path[i]] - p[path[i + 1]]); int q = len / c; len -= q * c, ans += (tot - vis[pos]) * q; return ans + work(path[tot], path[tot - 1], len); } } int main() { int T; read(T); while (T--) { read(n), read(m); for (int i = 1; i <= n; i++) read(p[i].x), read(p[i].y); for (int i = 1; i <= n; i++) { int tot = 0; for (int j = 1; j <= n; j++) if (i != j) a[i][++tot] = (info) {j, dist(p[i] - p[j]), PolarAngle(p[j] - p[i])}; sort(a[i] + 1, a[i] + tot + 1, cmp); for (int j = 1; j <= tot; j++) { a[i][j + tot] = a[i][j]; a[i][j + tot].alpha += 2 * pi; a[i][j + tot * 2] = a[i][j]; a[i][j + tot * 2].alpha += 4 * pi; } reverse(a[i] + 1, a[i] + tot * 3 + 1); int pos = 1; for (int j = 1; j <= tot; j++) { while (a[i][j].alpha - a[i][pos].alpha <= pi - eps) pos++; home[i][a[i][j].pos] = pos; } } for (int i = 1; i <= m; i++) { read(s.x), read(s.y); read(t.x), read(t.y); read(l); int tot = 0; static info tmp[MAXN]; tmp[++tot] = (info) {n + 1, l, PolarAngle(t - s)}; for (int j = 1; j <= n; j++) tmp[++tot] = (info) {j, dist(p[j] - s), PolarAngle(p[j] - s)}; sort(tmp + 1, tmp + tot + 1, cmp); for (int j = 1; j <= tot; j++)