【BZOJ5099】[POI2018]Pionek 几何+双指针

【BZOJ5099】[POI2018]Pionek

Description

在无限大的二维平面的原点(0,0)放置着一个棋子。你有n条可用的移动指令,每条指令可以用一个二维整数向量表示。每条指令最多只能执行一次,但你可以随意更改它们的执行顺序。棋子可以重复经过同一个点,两条指令的方向向量也可能相同。你的目标是让棋子最终离原点的欧几里得距离最远,请问这个最远距离是多少?

Input

第一行包含一个正整数n(n<=200000),表示指令条数。

接下来n行,每行两个整数x,y(|x|,|y|<=10000),表示你可以从(a,b)移动到(a+x,b+y)。

Output

输出一行一个整数,即最大距离的平方。

Sample Input

5
2 -2
-2 -2
0 2
3 1
-3 1

Sample Output

26

HINT

题解:假如我们已经确定了最终向量的方向,那么我们就会选择所有在这个方向上投影为正的向量。于是我们将所有向量按极角排序,然后枚举所有方向,用前缀和维护向量的和。可以先将序列倍长,然后用双指针法扫一遍即可。

不过需要注意的是,我们枚举的方向不仅是所有向量的方向,还有所有向量之间间隔的方向,所以我们在每个指针移动的时候都更新一下答案即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=200010;
int n;
ll ans;
struct node
{
	int x,y;
	double a;
}p[maxn<<1];
ll sx[maxn<<1],sy[maxn<<1];
bool cmp(const node &a,const node &b)
{
	return a.a<b.a;
}
inline void check(int l,int r)
{
	if(l<=r)	ans=max(ans,(sx[r]-sx[l-1])*(sx[r]-sx[l-1])+(sy[r]-sy[l-1])*(sy[r]-sy[l-1]));
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)	f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+(gc^‘0‘),gc=getchar();
	return ret*f;
}
int main()
{
	n=rd();
	int i,j;
	for(i=1;i<=n;i++)	p[i].x=rd(),p[i].y=rd(),p[i].a=atan2(p[i].x,p[i].y),p[i+n]=p[i],p[i+n].a+=2*pi;
	sort(p+1,p+2*n+1,cmp);
	for(i=1;i<=2*n;i++)	sx[i]=sx[i-1]+p[i].x,sy[i]=sy[i-1]+p[i].y;
	for(i=j=1;i<=2*n;i++)
	{
		for(;j<i&&p[j].a<=p[i].a-pi;j++,check(j,i-1));
		check(j,i);
	}
	for(;j<=2*n;check(j,2*n),j++);
	printf("%lld",ans);
	return 0;
}//2 1 10 1 -10
时间: 2024-08-01 17:26:31

【BZOJ5099】[POI2018]Pionek 几何+双指针的相关文章

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

几何+双指针 题目大意:现在有 \(n\) 个向量,请你选出来一些向量使它们的和的长度最大,输出最大值的平方. 假如我们已经知道了最终向量的方向,我们要想使长度最大,就需要将所有投影在最终向量正方向上的向量都加起来. 所以我们可以按角度枚举最终向量的方向,我们需要加起来的就是一段移动的区间,我们可以用双指针来维护加起来的向量. 因为最终向量的方向有可能是给出的向量,也有可能是向量之间间隔的方向,所以每次移动指针的时候都要更新一下答案. 因为开始给出的向量不一定有序,所以我们需要先将向量排序. #

[POI2018]Pionek

[POI2018]Pionek 题目大意: 在无限大的二维平面的原点放置着一个棋子.你有\(n(n\le2\times10^5)\)条可用的移动指令,每条指令可以用一个二维整数向量表示.请你选取若干条指令,使得经过这些操作后,棋子离原点的距离最大. 思路: 将所有向量极角排序,然后你选取的向量一定是里面连续的一段,由于所有向量排成一个环,所以要复制一遍接在后面,最后用尺取法枚举左右端点即可. 时间复杂度\(\mathcal O(n\log n)\). 源代码: #include<cmath>

URAL - 1963(几何)

不知道是不是几何题,反正就是找对称,值得注意的是,对称轴不一定过点,还可能在边上 #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; const double mm=1e-7; double x[10],y[10]; bool deng(double a,double

hdu_5806_NanoApe Loves Sequence Ⅱ(双指针)

题目链接:hdu_5806_NanoApe Loves Sequence Ⅱ 题意: 给你一段数,问你有多少个区间满足第K大的数不小于m 题解: 直接双指针加一下区间就行 1 #include<cstdio> 2 #include<algorithm> 3 #define F(i,a,b) for(int i=a;i<=b;i++) 4 using namespace std; 5 typedef long long ll; 6 const int N=2e5+7; 7 in

如何让你的UWP应用程序无缝调用几何作图

有时候需要编辑一些几何图形,如三角形,圆锥曲线等,在UWP应用中加入这些几何作图功能是件费时间又很难做好的事.其实Windows 10 应用商店中已有一些专业的几何作图工具了,那么能借来一用吗?答案是肯定的. UWP中,微软为Windows.System.Launcher启动器新增了很多的功能,以前只能启动App,打开指定扩展名文件,对uri协议的解析,以及当启动的应用没有安装时则会提示前往商店下载等. 如今,微软丰富了Launcher的功能,通过新增的LaunchUriForResultsAs

抛物线的几何性质(传统几何法推导)

抛物线有很多几何性质,网上也有不少关于这些性质的推导的文章,不过几乎清一色地都是用的解析几何的方法.联立方程,导出根与系数的关系,算算算算算…… 但是,与同样是二次曲线的椭圆和双曲线不同,圆和抛物线的几何性质非常「好」,不用坐标法,也能推出很多结论.不过相比具有完美对称性的圆来说,抛物线还是逊色了许多.圆的切线很容易用几何条件去描述(容易用反证法证出圆的切线垂直于过切点的直径),而抛物线的切线虽然也容易用几何条件描述,但相关结论却难以用纯几何法证出.所以涉及切线问题时,还是需要用坐标法证明一个重

大图标+不规则几何创造不同风格

设计了一套医用图标,运用超大线性图标与不规则几何背景相结合的方式,可以发现也是一种可以尝试的方式.用超大线性图标作为内容的和信息的标识,生动易理解(这里融合卡通风味),与此同时用色彩柔和的不规则几何图形作为背景,加以衬托,提升视觉感,值得尝试,向大家推荐.          我这边设计了两套,一套是彩色的,一套的蓝色的,巧妙运用色彩的搭配.透明度的搭配,可以创作出不同效果. 将图标运用到界面上,主页面直接用大图标: 404页面小动画:

The Doors 最短路 + 简单几何

The Doors 题目抽象:给你一些点,和一些阻碍连边的线段.问原点到终点最短的几何距离. 分析:预处理见图之后,跑最短路. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 using namespace std; 6 const int INF = 0X5FFFFFFF; 7 const int MS = 1005; 8 const i

【几何模板加点小思路】hdu-4998 Rotate

用几何模板敲的,也有直接公式推的,追求短代码的可以点右上角小红了...... 题意就是想想一个物体分别做绕某一点(给出坐标)旋转p度(给出角度)后,其位置等价于绕哪一点旋转多少度,输出该等价点及其等价角度. 其实就是找两个定点,然后看这两个定点旋转后到了哪,分别连接原点与旋转后的点会得到两条线段,两条线段垂直平分线的交点即是等价后绕其旋转的点,再将该交点与任一原点及其旋转后的点连接得到的夹角(咖啡色角)即等价后的旋转角度. 附代码 1 #include <cstdio> 2 #include