Description
在无限大的二维平面的原点(0,0)放置着一个棋子。你有n条可用的移动指令,每条指令可以用一个二维整数向量表
示。每条指令最多只能执行一次,但你可以随意更改它们的执行顺序。棋子可以重复经过同一个点,两条指令的方
向向量也可能相同。你的目标是让棋子最终离原点的欧几里得距离最远,请问这个最远距离是多少?
第一行包含一个正整数n(n<=200000),表示指令条数。
接下来n行,每行两个整数x,y(|x|,|y|<=10000),表示你可以从(a,b)移动到(a+x,b+y)。
Solution
假如我们知道了最终和向量的方向,那么答案就是选取向量在这个方向上投影的长度之和
由此可以得出一个结论,我们一定只会从某个向量开始顺时针连续选取一段向量,并且最大的夹角不超过180°
于是乎极角排序然后两个指针扫就没了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef long long LL;
const double pi=acos(-1);
const double eps=1e-13;
const int N=400005;
struct pos {
LL x,y; double arc;
LL operator *(pos b) const {
return x*b.y-y*b.x;
}
pos operator +(pos b) const {
return (pos) {x+b.x,y+b.y};
}
pos operator -(pos b) const {
return (pos) {x-b.x,y-b.y};
}
LL len() {
return x*x+y*y;
}
} p[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
bool cmp(pos a,pos b) {
return a.arc<b.arc;
}
int main(void) {
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
int n=read(),cnt=0;
rep(i,1,n) {
int x=read(),y=read();
if (1LL*x*x+1LL*y*y) {
p[++cnt]=(pos) {x,y,atan2(x,y)};
}
} n=cnt;
std:: sort(p+1,p+n+1,cmp);
rep(i,1,n) p[i+n]=p[i],p[i+n].arc=p[i].arc+2*pi;
pos ans=(pos) {0,0};
LL prt=0;
for (int l=1,r=1;l<=n;) {
while (r<l+n&&(p[r].arc-p[l].arc<=pi+eps)) {
ans=ans+p[r++];
prt=std:: max(prt,ans.len());
}
ans=ans-p[l++];
prt=std:: max(prt,ans.len());
}
printf("%lld\n", prt);
return 0;
}