【题目链接】
【思路要点】
- 如果我们得知了最终答案的方向,那么显然,我们会选取在该方向上投影为正的向量作为答案,而放弃投影为负的向量。
- 虽然方向是无法枚举的,但不难发现连续的一些方向导致我们选择的向量集合是相同的,我们实际上只需要枚举这样的向量集合就可以了。
- 将向量极角排序,并复制一份,用Two Pointers维护当前的向量集合即可。
- 时间复杂度\(O(NLogN)\)。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 400005; const double pi = acos(-1); 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 info {int x, y; double r; } a[MAXN]; bool operator < (info a, info b) {return a.r < b.r; } long long calc(long long x, long long y) {return x * x + y * y; } int main() { int n; read(n); for (int i = 1; i <= n; i++) { read(a[i].x), read(a[i].y); a[i].r = atan2(a[i].y, a[i].x); } sort(a + 1, a + n + 1); for (int i = 1; i <= n; i++) a[i + n] = a[i], a[i + n].r += 2 * pi; int m = n, r = 1; n *= 2; long long ans = 0, x = 0, y = 0; for (int l = 1; l <= n; l++) { while (r <= n && r - l < m && a[r].r - a[l].r <= pi) { x += a[r].x; y += a[r].y; r++; chkmax(ans, calc(x, y)); } x -= a[l].x; y -= a[l].y; chkmax(ans, calc(x, y)); } writeln(ans); return 0; }