P9465

P9465 [EGOI2023] Find the Box / 找箱子

神秘牛牛题,在无数次失败后终找到方向。

注意到只能询问两次,条件很紧,每次只会得到机器人最后的方位,也就只会得到至多两个坐标。

一个想法是找到一个双射,再修正一些不合法的地方。

接下来你需要极高的注意力。

我们肯定是要围绕箱子来定位,以 \(4 \times 5\) 的图举例,默认左上角为 \((1,1)\)

首先我们把左侧和下侧的点排掉:(红色位置)
image

具体方法为向下走 \(n-1\) 步,再向右走 \(m-1\) 步,如果没走到 \((n,m)\) 则合法,否则根据位置推箱子位置即可。

然后我们按照蓝色路线来走,那么在第两列,如果遇到箱子,可能会在绿点停下,否则就会走到紫色点。

image

接下来就是最智慧的时候,我们为了达到双射的目的,那我们就一定不能让绿点和紫点走到一起,否则就没办法区分两个箱子了。

注意到绿色点的含义就是在箱子前面停下,那我们围绕着箱子思考。

要区分开绿点和紫点,可以先将两色分在不同的列,绿色点的上方是箱子,可以很好的利用它。

一种可行的方案为向左,向上,向右。这样就会变成:

image

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

image

那第三列呢,是否可以用类似的手段?读者可以自己手玩推一下。

最后一列可能稍显特殊:还是先往上走,进行智慧操作,那我们所有的绿点都会来到对应箱子的左边,正好形成了一个双射!

image

直接输出即可。

代码:

#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);
}
posted @ 2024-01-09 18:26  Hanghang007  阅读(36)  评论(0)    收藏  举报