题解:P12822 [NERC 2021] Interactive Treasure Hunt

· · 题解

upd:

[2025/10/28 17:06] 发现了代码中的错误,糖丸了

思路

数学题。

其实理论上 n,m 可以开到很大。

下文令 x_1\ge x_2y_1\ge y_2

对于两个点的坐标,我们可以把它看成一个四元一次方程组求解,现在的问题是如何找到四个方程。

因为有绝对值,所以我们可以想到取一些极值点来消除绝对值的影响。我们可以想到取 (1,1)(1,m)(n,1)(n,m) 中的两个点。

其中不难发现,(1,1)(n,m) 是等价的;(1,m)(n,1) 是等价的,我们这里取 (1,1)(1,m)

(1,1) 的询问答案为 a(1,m) 的询问答案为 b

则有:

\begin{cases} x_1+x_2+y_1+y_2=a+4\\ x_1+x_2-y_1-y_2=b+2-2m \end{cases}

于是,我们能求出:

\begin{cases} x_1+x_2=\frac{a+b}{2}+3-m\\ y_1+y_2=\frac{a-b}{2}+1+m \end{cases}

现在我们考虑如何求出 x_1-x_2,这样就可以根据 x_1+x_2 求出它们的值(y_1-y_2 同理)。

不难注意到,根据绝对值的性质,我们设询问为 (x,y),答案为 c=|x_1-x|+|x_2-x|+|y_1-y|+|y_2-y|

首先,我们先排除 y 对答案的影响,所以 y1,答案为 |x_1-x|+|x_2-x|+y_1-1+y_2-1=c。解得 |x_1-x|+|x_2-x|=c+1-\frac{a-b}{2}-m

我们要求 x_1-x_2,只要令 x_1\ge x\ge x_2 即可。 那么,如何找出符合条件的 x 呢?

注意到当 x 为中点时,满足上方的式子。又因为我们已经求出了 x_1+x_2=\frac{a+b}{2}+3-m,根据中点公式,得 x=\frac{a+b+6-2m}{4}

所以,答案为 x_1-\frac{a+b+6-2m}{4}+\frac{a+b+6-2m}{4}-x_2=c+1-\frac{a-b}{2}-m,解得 x_1-x_2=c+1-\frac{a-b}{2}-m.

于是,我们有如下式子:

\begin{cases} x_1+x_2=\frac{a+b}{2}+3-m\\ x_1-x_2=c+1-\frac{a-b}{2}-m \end{cases}

解得:

\begin{cases} x_1=\frac{a+c}{2}+2-m\\ x_2=\frac{b-c}{2}-1 \end{cases} 我们发现最后 $x_1,x_2,y_1,y_2$ 的搭配不确定,所以先试一次 $(x_1,y_1)$,如果有宝藏那么另一个就是 $(x_2,y_2)$,否则两个宝藏就是 $(x_1,y_2)$ 和 $(x_2,y_1)$,总询问次数刚好 $7$ 次。 ## 代码 ```cpp //嘻嘻我又改代码了 #include<bits/stdc++.h> using namespace std; int main() { int t; cin>>t; cout<<flush; while(t--) { int n,m; cin>>n>>m; cout<<"SCAN 1 1"<<endl; int su; cin>>su; su+=4;//x1+x2+y1+y2 int sub; cout<<"SCAN 1 "<<m<<endl; cin>>sub; sub=-m-m+2+sub;//x1+x2-y1-y2 int sux,suy; sux=su+sub>>1;//x1+x2 suy=su-sub>>1;//y1+y2 int xmid,ymid; xmid=sux>>1;//中点 ymid=suy>>1; int subx,suby; cout<<"SCAN "<<xmid<<' '<<1<<endl; cin>>subx; subx=abs(2+subx-suy);//x1-x2 cout<<"SCAN "<<1<<' '<<ymid<<endl; cin>>suby; suby=abs(2+suby-sux);//y1-y2 int x1,y1,x2,y2; x1=sux+subx>>1; x2=sux-subx>>1; y1=suy+suby>>1; y2=suy-suby>>1; bool f; cout<<"DIG "<<x1<<' '<<y1<<endl; cin>>f; if(f==1) { cout<<"DIG "<<x2<<' '<<y2<<endl; cin>>f; continue; } else { cout<<"DIG "<<x1<<' '<<y2<<endl; cin>>f; cout<<"DIG "<<x2<<' '<<y1<<endl; cin>>f; continue; } } } ```