P9465
P9465 [EGOI2023] Find the Box / 找箱子
神秘牛牛题,在无数次失败后终找到方向。
注意到只能询问两次,条件很紧,每次只会得到机器人最后的方位,也就只会得到至多两个坐标。
一个想法是找到一个双射,再修正一些不合法的地方。
接下来你需要极高的注意力。
我们肯定是要围绕箱子来定位,以 \(4 \times 5\) 的图举例,默认左上角为 \((1,1)\)。
首先我们把左侧和下侧的点排掉:(红色位置)

具体方法为向下走 \(n-1\) 步,再向右走 \(m-1\) 步,如果没走到 \((n,m)\) 则合法,否则根据位置推箱子位置即可。
然后我们按照蓝色路线来走,那么在第两列,如果遇到箱子,可能会在绿点停下,否则就会走到紫色点。

接下来就是最智慧的时候,我们为了达到双射的目的,那我们就一定不能让绿点和紫点走到一起,否则就没办法区分两个箱子了。
注意到绿色点的含义就是在箱子前面停下,那我们围绕着箱子思考。
要区分开绿点和紫点,可以先将两色分在不同的列,绿色点的上方是箱子,可以很好的利用它。
一种可行的方案为向左,向上,向右。这样就会变成:

我们再往下走,就成功的讲绿点和紫色点分在了两列。

那第三列呢,是否可以用类似的手段?读者可以自己手玩推一下。
最后一列可能稍显特殊:还是先往上走,进行智慧操作,那我们所有的绿点都会来到对应箱子的左边,正好形成了一个双射!

直接输出即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#include "genshin.h"
int Num(int x,int y){return (x-1)*1024+(y-1);}
int play(int n,int m)
{
string s;
for(int i=1;i<n;i++)s+="v";
for(int i=1;i<m;i++)s+=">";
int y=query(s),x=y>>10;y&=1023;x++;y++;
if(x!=n||y!=m)
{
if(x<n)return Num(x+1,1);
else return Num(n,y+1);
}
string t;
for(int i=1;i<n;i++)t+="v";
for(int p=1;p<m;p++)
{
t+=">";
for(int i=1;i<n;i++)t+="^";
t+="<^>";
if(p<m-1)for(int i=1;i<n;i++)t+="v";
}
y=query(t);x=y>>10;y&=1023;x++;y++;
return Num(x,y+1);
}

浙公网安备 33010602011771号