[武汉加油] bzoj 5099: [POI2018]Pionek 几何+双指针

几何+双指针

题目大意:现在有 \(n\) 个向量,请你选出来一些向量使它们的和的长度最大,输出最大值的平方。

假如我们已经知道了最终向量的方向,我们要想使长度最大,就需要将所有投影在最终向量正方向上的向量都加起来。

所以我们可以按角度枚举最终向量的方向,我们需要加起来的就是一段移动的区间,我们可以用双指针来维护加起来的向量。

因为最终向量的方向有可能是给出的向量,也有可能是向量之间间隔的方向,所以每次移动指针的时候都要更新一下答案.

因为开始给出的向量不一定有序,所以我们需要先将向量排序。

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#define LL long long
using namespace std;
int n;
const double PI = acos(-1);
LL sx, sy, ans;
struct data
{
	LL x, y; double ang;
	friend bool operator <(const data & a,const data & b) {return a.ang < b.ang;}
}a[400010];
int main()
{
	cin >> n;
	for(int i = 1; i <= n; ++ i)scanf("%lld%lld", &a[i].x, &a[i].y), a[i].ang = atan2(a[i].y,a[i].x);
	sort(a + 1, a + 1 + n);
	for(int i = 1; i <= n; ++ i)a[n + i].x = a[i].x, a[n + i].y = a[i].y, a[n + i].ang = a[i].ang + 2 * PI;
	for(int l = 1, r = 1; l <= n; ++ l)
	{
		while(r < n + l && a[r].ang - a[l].ang < PI)sx += a[r].x, sy += a[r].y, ans = max(ans, sx * sx + sy * sy), ++ r;
		sx -= a[l].x, sy -= a[l].y, ans = max(ans, sx * sx + sy * sy);
	}
	cout << ans;
	return 0;
}
posted @ 2020-02-22 09:23  wljss  阅读(142)  评论(0编辑  收藏  举报