思路
我们可以通过题目上给出的图示看出,每一个等级的图是由前一个等级的图拼成的,拼接方式如图
因此在求解一个图上某一点的编号时,我们需要确定他是属于哪一块的,再进行坐标变换。
同时为了方便确定,我们将所有点的编号从0开始,同时坐标轴也会从0,开始。
接下来我们看坐标变化,以下图为例(图确实是太丑了-_-)
我们假设要求的编号为a,则它位于哪个区域就是z=a/block,同时知道它在上一级(小的)中的编号p=a%block,同时因为经常用,所以将len=2^{n-1};
则,我们求出他在上一级中的坐标
\[(x,y)=get(n-1,p)
\]
此时我们根据该点所在区域,来进行坐标转换
-
左上角,只需要只需要将坐标进行转换即可
\[(x,y)=>(y,x) \] -
右上角,只需要将y坐标增加len,即
\[(x,y)=>(x,y+len) \] -
右下角,只需将x,y坐标军增加len,即
\[(x,y)=>(x+len,y+len) \] -
左下角,稍微麻烦一些,画图进行理解
我们从图中便可以很好地的理解,变换即为
\[(x,y)=>(2*len-1-y,len-1-x) \] -
注意边界,当n=0时,代表我们找到了最小边界,即只有一个点,返回{0,0}即可
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
struct point
{
LL x,y;
};
point get(LL n,LL a)
{
if(n==0) return{0,0};//当n为0时,只有一个点{0,0}
LL block = 1ll<<2*n-2,len = 1ll<<n-1;
auto p = get(n-1,a%block);
LL z = a/block;
LL x = p.x,y = p.y;
if(z==0) return{y,x};
if(z==1) return{x,y+len};
if(z==2) return{x+len,y+len};
if(z==3) return{2*len-1-y,len-1-x};
}
int main()
{
int T;
cin>>T;
while(T--)
{
LL n,a,b;
cin>>n>>a>>b;
auto pa = get(n,a-1);//坐标从0开始算
auto pb = get(n,b-1);
LL dx = pa.x - pb.x,dy = pa.y-pb.y;
printf("%.0lf\n",sqrt(dx*dx+dy*dy)*10);
}
return 0;
}