[COCI2009]Dvapravca 计算几何
[COCI2009]Dvapravca
先给出考场上的\(O(n^3)\)乱搞方法:枚举一个蓝点和一个红点,找出过着两个点的直线,再枚举蓝点找出这条直线最多能往两边扩展多宽,最后枚举红点计算贡献。
注意在确定一条直线能往两边扩展多宽时不要求点到直线的距离,否则常数会太大,只要求竖直方向的距离就可以了。正确性显然,具体看代码。
现在有个重要的问题,求大佬来解决:如果直接这样写会被卡到65到70分,但是如果把蓝点和红点按\(x\)为第一关键字\(y\)为第二关键字从小到大排个序,就能得到90至100分(考试时用的评测机能跑到90分,洛谷神机上能切)。然而我不会证明这样究竟优化在哪里,求大佬证明。
#include<cstdio>
#include<algorithm>
#define R register
#define I inline
#define D double
using namespace std;
const int N=1003,inf=0x3f3f3f3f;
struct V{int x,y;}r[N],b[N];
struct L{D k,b;}f;
I int operator<(V a,V b){return a.x^b.x?a.x<b.x:a.y<b.y;}
I D min(D x,D y){return x<y?x:y;}
I int max(int x,int y){return x>y?x:y;}
I L lin(V a,V b){
if(a.x==b.x)
return (L){inf,0};
D k=(D)(b.y-a.y)/(b.x-a.x);
return (L){k,(D)a.y-k*a.x};
}
I D dst(V a){return f.k*a.x+f.b-a.y;}
int main(){
R int n,x,y,i,j,t,p=0,q=0,g,h,o=0;
R char c[2];
D d,u,v;
scanf("%d",&n);
for(i=1;i<=n;++i){
scanf("%d%d%s",&x,&y,c);
if(c[0]=='R')
r[++p]=(V){x,y};
else
b[++q]=(V){x,y};
}
sort(b+1,b+q+1),sort(r+1,r+p+1);//就是这里,不加会慢很多
for(i=1;i<=q;++i)
for(j=1;j<=p;++j){
f=lin(b[i],r[j]),u=v=inf,g=h=1;
for(t=1;t<=q;++t)
if(t^i)
if((d=dst(b[t]))>0)
u=min(u,d);
else
v=min(v,-d);
for(t=1;t<=p;++t)
if(t^j)
if((d=dst(r[t]))>0)
g+=d<u;
else
h+=-d<v;
o=max(o,max(g,h));
}
printf("%d",o);
return 0;
}
亲测如果没加sort应该是过不了的,xzz大神仙尝试把坐标系随机旋转了一下,变得更快了。所以这道题告诉我们一个经验:碰见不会的计算几何题,先随机旋转坐标系,再把点排一遍序,打起暴力更有自信!
还是放一下正解\(O(n^2 log n)\)的做法吧。考虑如果要求直线垂直于\(x\)轴,那么如果把点按刚才所说的排一遍序,要求的就是序列上连续的最长的\(1\)的个数(如果把红色视作\(1\))。由于直线可以倾斜,考虑旋转坐标系,当某两个点连线的斜率与当前\(y\)轴在原坐标系中的斜率相等时,这两个点在序列上的位置就会交换,这下可以用线段树来维护,由于最多交换\(O(n^2)\)次顺序,复杂度是\(O(n^2 log n)\)。
#include<cstdio>
#include<algorithm>
#define R register
#define I inline
#define D double
using namespace std;
const int N=1003,M=1000003,S=4003;
int f[N],n;
struct T{int f,l,r,d;}e[S];
struct V{int x,y,c;}p[N];
struct L{D k; int x,y;}q[M];
I int operator<(V a,V b){return a.x^b.x?a.x<b.x:a.y<b.y;}
I int operator<(L a,L b){return a.k>b.k;}
I int max(int x,int y){return x>y?x:y;}
I T operator+(T x,T y){
T z;
z.f=max(x.r+y.l,max(x.f,y.f)),z.d=x.d+y.d;
if(x.l==x.d)
z.l=x.d+y.l;
else
z.l=x.l;
if(y.r==y.d)
z.r=x.r+y.d;
else
z.r=y.r;
return z;
}
I void swp(int&x,int&y){x^=y,y^=x,x^=y;}
I void upd(int k,int v){e[k]=(T){v,v,v,1};}
I void bld(int k,int l,int r){
if(l==r){
upd(k,p[l].c);
return ;
}
R int p=k<<1,q=p|1,m=l+r>>1;
bld(p,l,m),bld(q,m+1,r),e[k]=e[p]+e[q];
}
void mdf(int k,int l,int r,int x,int v){
if(l==r){
upd(k,v);
return ;
}
R int p=k<<1,q=p|1,m=l+r>>1;
if(x<=m)
mdf(p,l,m,x,v);
else
mdf(q,m+1,r,x,v);
e[k]=e[p]+e[q];
}
int main(){
R int i,j,x,y,t=0,o;
R char c[2];
scanf("%d",&n);
for(i=1;i<=n;++i){
scanf("%d%d%s",&x,&y,c);
if(c[0]=='R')
p[i]=(V){x,y,1};
else
p[i]=(V){x,y,0};
}
sort(p+1,p+n+1);
for(i=1;i<=n;++i)
f[i]=i;
for(i=1;i<n;++i)
for(j=i+1;j<=n;++j)
q[++t]=(L){(D)(p[j].y-p[i].y)/(p[j].x-p[i].x),i,j};
sort(q+1,q+t+1),bld(1,1,n),o=e[1].f;
for(i=1;i<=t;++i){
x=f[q[i].x],y=f[q[i].y],swp(f[q[i].x],f[q[i].y]);
if(p[x].c^p[y].c)
swp(p[x].c,p[y].c),mdf(1,1,n,x,p[x].c),mdf(1,1,n,y,p[y].c),o=max(o,e[1].f);
}
printf("%d",o);
return 0;
}
[COCI2009]Dvapravca 计算几何的更多相关文章
- bzoj3086: Coci2009 dvapravca
Description 给定平面上的 N 个点, 其中有一些是红的, 其他是蓝的.现在让你找两条平行的直线, 使得在保证 不存在一个蓝色的点 被夹在两条平行线之间,不经过任何一个点, 不管是蓝色 ...
- luogu P4385 [COCI2009]Dvapravca
传送门 我真的弱,正解都不会还打了个错的暴力 考虑平行线与x轴平行,那么可以按照y为第一关键字升序,x为第二关键字升序排序,然后合法的一段红点就是连续的一段,答案也就是最大的连续红色段 推广到一般情况 ...
- P4385 [COCI2009]Dvapravca
首先特判掉蓝点数量\(<2\)的情况.没有蓝点答案就是\(n\),有一个蓝点可以枚举一个红点,选择过这个蓝点和红点的一条线和在无穷远处的平行线(即这条线对应的两个半平面). 这里认为过一个点是与 ...
- [洛谷P4385][COCI2009]Dvapravca(咕咕咕)
题目大意:很早以前做的题 题解: 卡点: C++ Code: #pragma GCC optimize("Ofast") #pragma GCC optimize("un ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- ACM/ICPC 之 计算几何入门-叉积-to left test(POJ2318-POJ2398)
POJ2318 本题需要运用to left test不断判断点处于哪个分区,并统计分区的点个数(保证点不在边界和界外),用来做叉积入门题很合适 //计算几何-叉积入门题 //Time:157Ms Me ...
- HDU 2202 计算几何
最大三角形 Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submi ...
- ACM 计算几何中的精度问题(转)
http://www.cnblogs.com/acsmile/archive/2011/05/09/2040918.html 计算几何头疼的地方一般在于代码量大和精度问题,代码量问题只要平时注意积累模 ...
- hdu 2393:Higher Math(计算几何,水题)
Higher Math Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
随机推荐
- ASM Disk Discovery 最佳实践
ASM DISK 的Discovery PATH ASM实例的ASM_DISKSTRING初始化参数使用一个逗号分割的字符串限制ASM实例发现的DISK可以用于ASM DISK, 该字符串支持通配符如 ...
- UNIX高级环境编程(5)Files And Directories - 文件相关时间,目录文件相关操作
1 File Times 每个文件会维护三个时间字段,每个字段代表的时间都不同.如下表所示: 字段说明: st_mtim(the modification time)记录了文件内容最后一次被修改的时 ...
- JavaWeb定时器-Spring3.x及更高版本Task使用
大背景 现代的 Web 应用程序框架在范围和复杂性方面都有所发展,应用程序的每个底层组件也必须相应地发展.作业调度是现代系统中对 Java 应用程序的一般要求,而且也是对 Java 开发人员一贯的要求 ...
- 铁乐学python_day04-作业
1,写代码,有如下列表,按照要求实现每一个功能 li = ['alex', 'wusir', 'eric', 'rain', 'alex'] 计算列表的长度并输出 print(len(li)) 答:结 ...
- Ubuntu 14.04安装QQ2012
GTkqq ,pidginQQ........等多多少少都存在一定的缺陷和问题. linuxQQ 有各种版本,这里介绍两种:linuxQQ(基本已不支持) 和 wineQQ (推荐使用) 1 ---- ...
- 【原创】uwsgi中多进程+多线程原因以及串行化accept() - thunder_lock说明
如有不对,请详细指正. 最近再研究uwsgi如何部署python app,看uwsgi的文档,里面有太多的参数,但每个参数的解释太苍白,作为菜鸟的我实在是不懂.想搞清楚uwsgi的工作原因以及里面的一 ...
- JAVA 泛型通配符 ? EXTENDS SUPER 的用法
1. <? extends Hero> ArrayList heroList<? extends Hero> 表示这是一个Hero泛型或者其子类泛型heroList 的泛型可能 ...
- 02.Java入门
Java 是SUN(Starfard University Network)公司在1995年开发的一门完全面向对象的,开源的高级编程语言. Java的发展历史 1995年诞生,1996年发布第一个版本 ...
- Jmeter之post上传文件
上周五东西都收拾好了,然后被叫住加班,直接搞到凌晨一两点,原因是另一个项目的性能出了点问题.为此我抓包写了一下主业务流的接口,涉及到文件上传,记录一下吧. 一.创建线程组,添加各类组件 这个就不用说了 ...
- P2758 编辑距离
题目描述 设A和B是两个字符串.我们要用最少的字符操作次数,将字符串A转换为字符串B.这里所说的字符操作共有三种: 1.删除一个字符: 2.插入一个字符: 3.将一个字符改为另一个字符: !皆为小写字 ...