题意:给定平面上一个圆和一堆圆外的点,要求选出尽可能多的点使得它们之间两两连线都不和圆相交。保证任意两点连线不和圆相切。点数<=2000

这题是很久以前在某张课件上看见的。看了题解还搞了三小时,联赛滚粗既视感。

有个结论我是直接看的课件:“点和点连线不与圆相交”对应“这两个点所对的圆上的极角序区间相交但不相互包含”,并不会证,画画图好像是对的。

在直线上选择一些两两相交且不包含的区间[L1,R1],[L2,R2],[L3,R3]….,按左端点排序之后,必然有L1<L2<L3….<Ln<R1<…<Rn,然后课件让我枚举第一个区间是谁,按左端点排序后对右端点跑LIS,O(N^2logN). 这里认为左端点可以在圆上所在区间里逆时针走到所在区间的右端点。

但是我写了一发过不了样例,因为在一个环上选一些两两相交不重合的区间,并不一定存在一个区间把其他区间的左端点都包含起来,比如说把圆三等分成三个区间,再把每个区间稍微左右延长一点点。

懵逼…不过仔细观察,发现这个时候如果选了一个起始区间直接跑LIS,出错时一定是有一个区间左端点不被选中的起始区间包含,但这个区间的右端点绕回了起始区间。那么我们把这个区间变成它在圆上的补区间,好像就挺对的。

所以我们把“左端点不在起始区间但右端点在起始区间内”的区间变成它的补区间,也就是把左右端点交换一下,然后跑LIS就A了。这么做的原理是假如区间A和区间B相交且不包含,那么区间A的补区间也一定和区间B相交且不包含。但是,区间A,B都取补区间后不一定相交且不包含。所以跑完一遍LIS还得把交换过的左右端点恢复回去,实现时我写了一发时间戳标记每个区间是否被交换。

PS. 极角序区间预处理的时候注意所求极角的范围。

/**************************************************************
Problem: 4660
User: liu_runda
Language: C++
Result: Accepted
Time:5540 ms
Memory:944 kb
****************************************************************/ #include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=2005;
const double pi=3.14159265;
struct point{
double x,y;
void read(){
scanf("%lf %lf",&x,&y);
}
point(){
}
point(double _x,double _y){
x=_x;y=_y;
}
point operator-(const point &B)const{
return point(x-B.x,y-B.y);
}
}P[maxn];
double l[maxn],r[maxn];
double angle(point A){
return atan2(A.y,A.x);
}
int seq[maxn];int tot=0;
bool betw(double l,double r,double x){
if(l<r){
return l<x&&x<r;
}else{
return (x>l)||(x<r);
}
}
bool cmp1(const int &a,const int &b){
return l[a]<l[b];
}
double curl,curr;
bool cmp2(const int &a,const int &b){
if(a>curl&&b>curl)return l[a]<l[b];
else if(a<curr&&b<curr)return l[a]<l[b];
else return l[a]>curl;
}
double m[maxn];
double _r[maxn];
int lis(){
memset(m,0x42,sizeof(m));
m[0]=-1e30;
for(int i=1;i<=tot;++i){
_r[i]=r[seq[i]]-curl;
if(_r[i]<0)_r[i]+=2*pi;
}/*
for(int i=1;i<=tot;++i)printf("%.2f ",_r[i]);
printf("\n");
for(int i=1;i<=tot;++i){
printf("%.2f %.2f\n",l[seq[i]],r[seq[i]]);
}*/ int ans=0;double *pt;
for(int i=1;i<=tot;++i){
pt=upper_bound(m,m+tot+1,_r[i]);
if((pt-m)>ans)ans=pt-m;
*pt=_r[i];
}
return ans;
}
int T;
int mark[maxn];
int main(){
// freopen("4660.in","r",stdin);
// freopen("4660.out","w",stdout);
int n,R;
scanf("%d%d",&n,&R);
for(int i=1;i<=n;++i)P[i].read();
double tmp,delta;
for(int i=1;i<=n;++i){
tmp=angle(P[i]);delta=fabs(acos(R/sqrt(P[i].x*P[i].x+P[i].y*P[i].y)));
// printf("%.2f %.2f\n",tmp,delta);
l[i]=tmp-delta;r[i]=tmp+delta;
if(l[i]<-pi)l[i]+=pi*2;
if(r[i]>pi)r[i]-=pi*2;
}//printf("\n");
/* for(int i=1;i<=n;++i){
printf("%.2f %.2f\n",l[i],r[i]);
}//while(1);
printf("\n");*/
int ans=0,curans;
for(int i=1;i<=n;++i){//枚举起点
tot=0;
++T;
seq[++tot]=i;
for(int j=1;j<=n;++j){
if(i!=j&&betw(l[i],r[i],l[j])&&!betw(l[i],r[i],r[j]))seq[++tot]=j;
else if(i!=j&&betw(l[i],r[i],r[j])&&!betw(l[i],r[i],l[j])){
swap(l[j],r[j]);seq[++tot]=j;
mark[j]=T;
}
}
curl=l[i];curr=r[i];
if(l[i]<r[i])sort(seq+1,seq+tot+1,cmp1);
else sort(seq+1,seq+tot+1,cmp2);
curans=lis();
if(curans>ans)ans=curans;
for(int j=1;j<=tot;++j){
if(mark[j]==T)swap(l[j],r[j]);
}
}
printf("%d\n",ans);//while(1);
return 0;
} /*
5 8
-7 20
10 80
-7 26
-13 79
11 81
*/

  

Bzoj3663/4660 CrazyRabbit的更多相关文章

  1. 三倍经验——bzoj3663、4660、4206 Crazy Rabbit/最大团

    题目描述: 3663 4660 4206 题解: 第一眼:不成立的互相连边,然后用网络流求解无向图最小点覆盖! 好吧我不会. 正解: 每个点对应圆上的一段圆弧,长这样: 设对应圆弧$(l,r)$. 若 ...

  2. bzoj 4660 Crazy Rabbit——LIS解决“相交”限制的思想

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4660 想到一个点可以用它与圆的两个切点表示.并想到可以把切点极角排序,那么就变成环上的一些区 ...

  3. bzoj3663/4660CrazyRabbit && bzoj4206最大团

    题意 给出平面上N个点的坐标,和一个半径为R的圆心在原点的圆.对于两个点,它们之间有连边,当且仅当它们的连线与圆不相交.求此图的最大团. 点数<=2000,坐标的绝对值和半径<=5000. ...

  4. bzoj 3768: spoj 4660 Binary palindrome二进制回文串

    Description 给定k个长度不超过L的01串,求有多少长度为n的01串S满足: 1.该串是回文串 2.该串不存在两个不重叠的子串,在给定的k个串中. 即不存在a<=b<c<= ...

  5. 2018.10.30 一题 洛谷4660/bzoj1168 [BalticOI 2008]手套——思路!问题转化与抽象!+单调栈

    题目:https://www.luogu.org/problemnew/show/P4660 https://www.lydsy.com/JudgeOnline/problem.php?id=1168 ...

  6. bzoj3663

    几何+lis 很巧妙.直接做很困难,那么我们转化一下,把每个点能看见的圆弧画出来.只有这些圆弧相交时才满足条件. 那么也就是找出圆上尽量多两两相交的区间. 所以我们先按左端点极角排序,然后固定一个必须 ...

  7. [Keras] Develop Neural Network With Keras Step-By-Step

    简单地训练一个四层全连接网络. Ref: http://machinelearningmastery.com/tutorial-first-neural-network-python-keras/ 1 ...

  8. EChart数据的异步加载和更新

    ECharts是国内开发一款图标插件,在网页中我们经常要用到图标显示,直接引用十分方便. 直接到ECharts主页调用插件 <!DOCTYPE html> <html style=& ...

  9. 通用js地址选择器

    用js实现通用的地址选择器,省份,城市,地区自动关联更新 点击下面查看详细代码: http://runjs.cn/code/s8sqkhcv 关键地址库代码: var addr_arr = new A ...

随机推荐

  1. Linux 网络编程详解十二

    UDP的特点 --无连接 --基于消息的数据传输服务 --不可靠 --UDP更加高效 UDP注意点 --UDP报文可能会丢失,重复 --UDP报文可能会乱序 --UDP缺乏流量控制(UDP缓冲区写满之 ...

  2. 移动端页面(css)调试之“weinre大法”

    移动端页面调试一般分两步.第一步我们需要把本地(pc端)写的页面效果展现在移动端,一个很方便的办法是用 fiddler 作为代理,具体可以参考 如何用 fiddler 代理调试本地手机页面,这样我们就 ...

  3. 基于DDD的.NET开发框架 - ABP缓存Caching实现

    返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...

  4. js的原型链和constructor

    转载:http://www.108js.com/article/article1/10201.html?id=1092 请先瞻仰上边的这篇文章. 对象的原型链: box.__proto__.__pro ...

  5. SDRAM基础知识

    SDRAM知识普及 在学习SDRAM之前,必须先了解"SDRAM"这个概念性的东西,并有感性的认识转变到一种理性的认识,所谓理性的认识就是实质性的东西…….不多说,相信你已经迫不急 ...

  6. 使textarea支持tab缩进

    //textarea支持tab缩进 $("textarea").on( 'keydown', function(e) { if (e.keyCode == 9) { e.preve ...

  7. jquery总结

    id选择器只能选定第一个满足条件的元素 class选择器可以选定一类满足条件的元素 text(),html(),val(),attr()等操作类型的函数,作用对象是前面选择器选定的元素.选定的元素可能 ...

  8. 为什么要加入<!doctype html>这个文档声明——IE怪异模式

    调试了很久,发现了一个非常细微但又十分重要的问题,又一次我在对于文档声明类型的时候,声明了如下类型 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1 ...

  9. python学习笔记整理——dictView [未整理]

    Dictionary view objects简介 The objects returned by dict.viewkeys(), dict.viewvalues() and dict.viewit ...

  10. CSS选择器优先级排列

    CSS选择器的效率从高到低做了一个排序: 1.id选择器(#myid) 2.类选择器(.myclassname) 3.标签选择器(div,h1,p) 4.相邻选择器(h1+p) 5.子选择器(ul & ...