题意简述:在平面上有一个坐标 \((x_c,y_c)\) 和半径 \(r\) 都是整数的圆 \((1\leq r_c\leq \sqrt{x_c^2+y_c^2}-1)\),你可以询问不超过 \(60\) 次一个从原点出发的射线 \((0,0)\to (x,y)\) 与圆的距离(若相交,则返回 \(0\))。确定圆的坐标和半径。

\(|x_c|,|y_c|,r\le 10^5\),你需要保证 \(|x|,|y|\leq 10^6\)。

一道有趣的计算几何,思维含量并不是很高(*3300 有点离谱),就是写起来麻烦了些。比赛的时候花了四个小时写这题,结果发现前面两个半小时写的东西完全没有用(狂笑)。


Step 1:旋转坐标轴规避分类讨论

首先我们得确定这个圆的大致位置,也就是在哪个象限。因为如果对于四个象限分别分类讨论很麻烦,不如旋转坐标轴使得这个圆落在某些固定的象限,每次旋转 \(90^{\circ}\)。不妨将圆心旋转到 \(x\) 轴上方,且确保这个圆不经过第三象限,这是可以同时做到的:

我们可以通过询问 \((0,\pm i)\) 与 \((\pm i,0)\) 来确定圆和坐标轴是否有交。

  • 若没有交点,将坐标轴旋转使得圆落在第一象限。
  • 若有一个交点,将坐标轴旋转使得圆落在第一、二象限。
  • 若有两个交点,将坐标轴旋转使得圆落在第一、二、四象限。

不要忘了旋转后询问要转回来。比如我们将坐标轴顺时针旋转 \(90^{\circ}\) 后,询问时需要将坐标逆时针旋转 \(90^{\circ}\)。


Step 2:二分找到与圆相切的射线

由于圆心在 \(x\) 轴上方,询问交互库 \((0,x)\ (x<0)\) 的返回值 \(d_0\) 显然是 \(\sqrt{x_c^2+y_c^2}-r\):因为过圆心且垂直于射线的直线与射线没有交点,故最短距离为原点与圆心距离减去半径。

注意到根据三个方程我们可以直接解出 \((x,y,r)\),\(d_0=\sqrt{x_c^2+y_c^2}-r\) 已经是其中一个了。只需要再找到两个和圆距离 \(\neq d_0\) 且 \(\neq 0\) 的射线即可,称其为合法射线

但是我们不能随便询问!因为可以构造一个与 \(y=kx\) 非常相近且半径非常大的圆,例如与 \(y=-x\) 几乎相切的 \((50000,50000,70709)\),使得合法的射线范围非常小。因为一旦稍有偏移,我们询问到的是 \(d_0\),要么就是 \(0\)(上述例子中,只有 \(y=-x\) 和过原点的圆的两条切线之间所夹住的区域合法)。而我们不知道出题人会构造什么毒瘤数据,这也意味着我们不能询问固定的射线,这样是没有前途的。

但注意到距离切线非常近(指与切线夹角非常小且与圆相离的射线范围)的那一块区域是合法的,这启发我们二分出几乎与圆相切(但与圆相离)的两条射线 \(a:(0,0)\to (x_a,y_a)\) 与 \(b:(0,0)\to (x_b,y_b)\)。具体怎么二分呢,想象一个 \((2\times10^6)\times (2\times 10^6)\) 的盒子包住了整个坐标轴。我们在从左逼近时,若返回值 \(>\rm eps\) 则认为与圆相离,向顺时针方向二分,否则认为与圆相交或相切,向逆时针方向二分。从右逼近则相反。

代码中寻找射线 \(a\) 只在第二象限内(原因在接下来会提到),因为圆心在 \(x\) 轴上方导致就算二分不到与切线很相近的位置,我们也可以找到不同于 \(d_0\) 和 \(0\) 的其它合法射线(想一想,为什么?Hint:\(10^6>10^5\))。

Step 3:枚举 \(r\) 并根据 \(d_0,d_a\) 求出 \((x,y)\)

根据圆与 \(a\) 的距离 \(d_a\) 以及 \(d_0\) 仍不足以确定这个圆:两个方程,三个变量。如果再加上 \(d_b\) 那么算起来太麻烦,精度爆炸怎么办?没有关系,注意到 \(r\) 是整数并且 \(\leq 10^5\),我们直接枚举 \(r\) 并根据 \(d_0,d_a\) 算出 \(x,y\),再检查当前的圆 \((x,y,r)\) 与 \(b\) 的距离是否等于 \(d_b\)。若相等则说明 \((x,y,r)\) 即为答案。这样精度就很优秀了。

怎么算 \(x,y\):注意到射线 \(a\) 在第二象限内,设其与 \(x\) 轴负半轴的夹角为 \(\alpha\),先将坐标轴逆时针旋转 \(\alpha\) 使得 \(a\) 落在 \(x\) 轴负半轴上,我们设原来的 \(x,y\) 经过这样的变换后新的坐标为 \(x_T,y_T\)。我们很容易求出 \(x_T,y_T\):\(y_T\) 就是 \(r+d_a\),而 \(d_0\) 在这样的变换下是不会变的(旋转变换不改变两点之间的距离),因此 \(x_T^2+y_T^2=(r+d_0)^2\)。解得 \(|x_T|\) 后还需要确定符号:究竟是在新坐标系的第一象限还是第二象限。这个可以通过求得 \(a\) 后询问交互库 \((-x_a,-y_a)\) 得到 \(d_a'\),若 \(d_a<d_a'\) 说明 \(T\) 在第二象限,令 \(x_T\gets -|x_T|\),否则 \(T\) 在第一象限,\(x_T\gets |x_T|\)。

注意到我们将坐标轴逆时针旋转了 \(\alpha\) 角度,因此还要顺时针转回来。将其乘以

\[\begin{bmatrix}\cos (-\alpha)&-\sin(-\alpha)\\\sin (-\alpha)&\cos(-\alpha)\end{bmatrix}
\]

\[\begin{bmatrix}\cos \alpha&\sin\alpha\\-\sin \alpha&\cos\alpha\end{bmatrix}
\]

即可。根据 \(\alpha\in\left[0,\dfrac \pi 2\right]\) 进行了化简。至于怎么算圆到射线的距离,点积搞搞就好了吧,实在不行可以像我一样上网现学。

至此,本题被我们完美解决。时间复杂度 \(\mathcal{O}(r)\),询问次数为 \(2\log V\),其中 \(V\) 是询问最大范围。代码中使用 \(V=2\times 10^5\),一个测试点大约询问 \(50\) 次。

const ld eps=1e-5;
const ll N=2e5; ld max(ld x,ld y){return x>y?x:y;}
bool Eq(ld x,ld y){return fabs(x-y)<eps;}
bool Isz(ld x){return fabs(x)<eps;} ld up,down,left,right;
ld dis(ld x1,ld y1,ld x2,ld y2){
return sqrt((x1-x2)*(x1-x2)+((y1-y2)*(y1-y2)));
}
ld dis(ld x1,ld y1,ld x2,ld y2,ld r){
ld dot=x1*x2+y1*y2,d=dis(0,0,x2,y2);
if(dot<eps)return max((ld)0,d-r);
ld need=dot/dis(0,0,x1,y1);
return max((ld)0,sqrt(d*d-need*need)-r);
} int swp,type;
void ref(int &x,int &y){int t=y; y=x,x=-t;}
ld query(int x,int y){
for(int j=1;j<=swp;j++)ref(x,y);
std::cout<<"? "<<x<<" "<<y<<std::endl;
ld res; std::cin>>res;
return res;
}
void answ(int x,int y,int r){
for(int j=1;j<=swp;j++)ref(x,y);
std::cout<<"! "<<x<<" "<<y<<" "<<r<<std::endl,exit(0);
}
void answer(ld x,ld y,ld r){
int xx=x<0?x-eps:x+eps;
int yy=y<0?y-eps:y+eps;
return answ(xx,yy,r+eps);
} int main(){
up=query(0,10),down=query(0,-10);
left=query(-10,0),right=query(10,0);
type=Isz(up)+Isz(down)+Isz(left)+Isz(right);
if(type==0){
ld mx=max(max(up,down),max(left,right));
if(down==mx&&right==mx)swp=1;
if(right==mx&&up==mx)swp=2;
if(up==mx&&left==mx)swp=3;
}
if(type==1){
if(Isz(left))swp=1;
if(Isz(down))swp=2;
if(Isz(right))swp=3;
}
if(type==2){
if(Isz(left)&&Isz(up))swp=1;
if(Isz(down)&&Isz(left))swp=2;
if(Isz(right)&&Isz(down))swp=3;
}
up=query(0,10),down=query(0,-10);
left=query(-10,0),right=query(10,0);
ll l=1,r=N*2-1,xx,yy; ld res;
while(l<r){
ll m=l+r>>1;
xx=-std::min(N,m),yy=N-max(0ll,m-N);
(res=query(xx,yy))>1e-6?r=m:l=m+1;
}
xx=-std::min(N,l),yy=N-max(0ll,l-N);
ld upl=query(xx,yy),downr=query(-xx,-yy);
ld mdis=std::min(upl,downr); ll xx2,yy2; l=1,r=N*3-1;
while(l<r){
ll m=(l+r>>1)+1;
xx2=std::min(N,m),yy2=-N+max(0ll,m-N);
(res=query(xx2,yy2)>1e-6)?l=m:r=m-1;
}
xx2=std::min(N,l),yy2=-N+max(0ll,l-N);
res=query(xx2,yy2);
for(int r=1;r<=1e5;r++){
ld y=mdis+r,x=sqrt((down+r)*(down+r)-y*y);
ld sn=(ld)fabs(yy)/(ld)(sqrt(xx*xx+yy*yy));
ld cs=(ld)fabs(xx)/(ld)(sqrt(xx*xx+yy*yy));
if(Eq(mdis,upl))x=-x;
ld x0=x*cs+y*sn,y0=-x*sn+y*cs; x=x0,y=y0;
if(Eq(res,dis(xx2,yy2,x,y,r)))answer(x,y,r);
}
return 0;
}
// qwq Kelly qwq

CF1578I Interactive Rays:ICPC WF Moscow Invitational Contest I 题解的更多相关文章

  1. 2018 ICPC Pacific Northwest Regional Contest I-Inversions 题解

    题目链接: 2018 ICPC Pacific Northwest Regional Contest - I-Inversions 题意 给出一个长度为\(n\)的序列,其中的数字介于0-k之间,为0 ...

  2. ACM ICPC 2015 Moscow Subregional Russia, Moscow, Dolgoprudny, October, 18, 2015 G. Garden Gathering

    Problem G. Garden Gathering Input file: standard input Output file: standard output Time limit: 3 se ...

  3. ACM ICPC 2015 Moscow Subregional Russia, Moscow, Dolgoprudny, October, 18, 2015 D. Delay Time

    Problem D. Delay Time Input file: standard input Output file: standard output Time limit: 1 second M ...

  4. 2018-2019 ICPC, NEERC, Southern Subregional Contest

    目录 2018-2019 ICPC, NEERC, Southern Subregional Contest (Codeforces 1070) A.Find a Number(BFS) C.Clou ...

  5. ACM ICPC Central Europe Regional Contest 2013 Jagiellonian University Kraków

    ACM ICPC Central Europe Regional Contest 2013 Jagiellonian University Kraków Problem A: Rubik’s Rect ...

  6. Codeforces 2018-2019 ICPC, NEERC, Southern Subregional Contest

    2018-2019 ICPC, NEERC, Southern Subregional Contest 闲谈: 被操哥和男神带飞的一场ACM,第一把做了这么多题,荣幸成为7题队,虽然比赛的时候频频出锅 ...

  7. 2016 NEERC, Moscow Subregional Contest K. Knights of the Old Republic(Kruskal思想)

    2016 NEERC, Moscow Subregional Contest K. Knights of the Old Republic 题意:有一张图,第i个点被占领需要ai个兵,而每个兵传送至该 ...

  8. 2019-2020 ICPC, Asia Jakarta Regional Contest (Online Mirror, ICPC Rules, Teams Preferred)

    2019-2020 ICPC, Asia Jakarta Regional Contest (Online Mirror, ICPC Rules, Teams Preferred) easy: ACE ...

  9. ICPC North Central NA Contest 2018

    目录 ICPC North Central NA Contest 2018 1. 题目分析 2. 题解 A.Pokegene B.Maximum Subarrays C.Rational Ratio ...

随机推荐

  1. OO第四单元作业总结及课程总结

    一.本单元作业架构设计 1.第一次作业 本单元首次接触到UML以及相关概念,在面对第一次作业时首先花了很大功夫去阅读官方接口中各种UmlElement的代码,才理解了输入的模型元素中各属性的含义.总的 ...

  2. Kruskal重构树-进阶

    例题一:区间最小生成树(NKOJ P8439) 简要题意: 一个n个点m条边的无向图,点编号1到n,边编号1到m.边有边权. 有q次操作,操作分两种: 1.k x y z:修改第k条边,使其连接的两点 ...

  3. 主集天线和分集天线——4G天线技术

    主集天线和分集天线 分集接收技术是一项主要的抗衰落技术,可以大大提高多径衰落信道传输下的可靠性,在实际的移动通信系统中,移动台常常工作在城市建筑群或其他复杂的地理环境中,而且移动的速度和方向是任意的. ...

  4. OpenWrt编译问题记录

    错误一.config.status: error: cannot find input file: `xmetadataretriever/Makefile.in' configure: creati ...

  5. 内核驱动编译之Makefile shell pwd路径问题

    一般我们在写Makefile的时候为了获取到当前Makefile所在的文件夹路径,会使用TopDIR ?= $(shell pwd)来定义,后续的文件路径都是基于此TopDIR基础上使用. 今天在移植 ...

  6. hdu 2176 取(m堆)石子游戏 (裸Nim)

    题意: m堆石头,每堆石头个数:a[1]....a[m]. 每次只能在一堆里取,至少取一个. 最后没石子取者负. 先取者负输出NO,先取胜胜输出YES,然后输出先取者第1次取子的所有方法.如果从有a个 ...

  7. clnt_create: RPC: Port mapper failure - Unable to receive: errno 111 (Connection refused)

    clnt_create: RPC: Port mapper failure - Unable to receive: errno 111 (Connection refused) 关闭防火墙,可以连, ...

  8. Jenkins+SVN+Maven+testNG管理项目

    1.登录访问:http://localhost:8080/jenkins 2.系统管理 => 全局工具配置 => ADD JDK  AND  Add Maven 3.安装SVN插件:系统管 ...

  9. 浅讲.Net 6 并与之前版本写法对比

    介绍 昨天vs2022正式版已经推出了,估计很多人已经下载并开始创建.Net 6 开始尝鲜了, 本节我简要的给大家介绍一下.Net 6的一些改动. 正文 本次.Net6带来最明显的变化就是: 采用顶级 ...

  10. Spring @Component生成bean名称的规则(当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致

    正确注入方式: @Autowired private TFeeMapper TFeeMapper; 错误注入方式 @Autowired private TFeeMapper tFeeMapper; 这 ...