题解:P10735 [NOISG2019 Prelim] Square or Rectangle?
前言
这是一道交互题,不了解交互题的推荐先看洛谷交互题功能说明、OI Wiki对交互题的说明、P1733 猜数(IO交互版)<--交互入门1、P1947 猜数<--交互入门2。
题意
有
思路
我们可以假设所有的矩形都是正方形,以
对于网格中任意一点,都有可能成为涂色矩形中的一点,为了不浪费询问次数,我们可以每隔
那为什么 (不排除毒瘤样例)。这样对于
接下来,如果找到了某些点是涂色的,就用
如果没有找到涂色的点,那这个矩形一定是在边缘(可以参考上图),我们再对边缘判断即可。
如果找到了,用二分找左上点上面的边和左边的边,找右下点下面的边,然后可以通过计算得知右边的边,此方法最多的询问次数为
code
#include <bits/stdc++.h>
using namespace std;
extern "C" bool inside_shape(int x,int y);
int up(int x,int y,int s)//向上走,从 x+1 到 s
{
int l=x+1,r=s,mid,ans=x;
while(l<=r)
{
mid=(l+r)/2;
if(inside_shape(mid,y))
{
ans=mid;
l=mid+1;
}
else
{
r=mid-1;
}
}
return ans;
}
int down(int x,int y,int s)//向下走,从 s 到 x-1
{
int l=s,r=x-1,mid,ans=x;
while(l<=r)
{
mid=(l+r)/2;
if(inside_shape(mid,y))
{
ans=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
return ans;
}
int left(int x,int y,int s)//向左走,从 s 到 y-1
{
int l=s,r=y-1,mid,ans=y;
while(l<=r)
{
mid=(l+r)/2;
if(inside_shape(x,mid))
{
ans=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
return ans;
}
int right(int x,int y,int s)//向右走,从 y+1 到 s
{
int l=y+1,r=s,mid,ans=y;
while(l<=r)
{
mid=(l+r)/2;
if(inside_shape(x,mid))
{
ans=mid;
l=mid+1;
}
else
{
r=mid-1;
}
}
return ans;
}
extern "C" bool am_i_square(int N, int Q)
{
int x_1=N+1,x_2=0,y_1=N+1,y_2=0;
int plus=ceil(0.2*N);//对应上文变量 p
for(int i=plus;i<N;i+=plus)
{
for(int j=plus;j<N;j+=plus)
{
if(inside_shape(i,j))
{
x_1=min(x_1,i);
x_2=max(x_2,i);
y_1=min(y_1,j);
y_2=max(y_2,j);
}
}
}
if(x_2)
{
int new_x_1=0,new_y_1=0,new_x_2=0,new_y_2=0;
new_x_1=down(x_1,y_1,x_1-plus+1);//x_1 和 y_1 是左上点
new_y_1=left(x_1,y_1,y_1-plus+1);
new_x_2=up(x_2,y_2,min(N,x_2+plus));//x_2 和 y_2 是右下点
// new_y_2=right(x_2,y_2,min(N,y_2+plus)); 会超限哦~
new_y_2=new_y_1+(new_x_2-new_x_1);
return new_x_2<=N and (inside_shape(new_x_2,new_y_2) and (new_y_2==N or !inside_shape(new_x_2,new_y_2+1)));//要求:这个值不能大于 N,计算的右下点被涂色,右下点右边的点未涂色
}
if(inside_shape(N,N))//特判
{
return !inside_shape(N-plus,N) and !inside_shape(N,N-plus);
}
int new_x=0,new_y=0;
for(int i=plus;i<N;i+=plus)
{
if(inside_shape(i,N))
{
new_x=down(i,N,i-plus+1);
return !inside_shape(new_x+plus,N);//如果(i,N)存在,那么(找到的下边+p,N)一定不存在,如果返回为 1 就是这个矩形不是正方形,
}
}
for(int i=plus;i<N;i+=plus)
{
if(inside_shape(N,i))
{
new_y=left(N,i,i-plus+1);
return !inside_shape(N,new_y+plus);//同上
}
}
return 0;
}
后记
交互题太好玩啦,本人千疮百孔的调试代码。