从上图可以得出城市等级N和房屋数量的关系:
房屋数量=22N
要求两个城市之间的距离,我们就需要计算两个城市的坐标。每一座N级城市由4座N-1级城市组成,所以我们想要计算calc(N,M),M编号的房屋在N级城市的编号,可以转化成求对应编号在N-1级城市的坐标。
M mod 22N-2:M编号的城市在N-1级的城市未经过翻转变化前,对应位置的编号。
M / 22N-2:M编号的房屋在4座N-1级的城市中的哪一块区域。对应区域如下:
求得N-1级的房屋位置(x,y)后,我们需要对根据4个区域进行坐标变化来得到M编号在N级城市的位置,x为行号,y为列号。
方法一:以图的左上角为坐标原点,即所有坐标在同一象限。
区域0: 将原城市顺时针旋转90度,再水平翻转
这里使用旋转矩阵进行坐标变换,在二维空间中,正角表示逆时针旋转。顺时针旋转90度为负角,
(x,y)->(-y,x)
水平翻转后,
(-y,x)->(y,x),纵坐标不变,横坐标符号改变。
区域1: 将原城市向右平移N-1级城市的边长,边长len与等级N的关系为
len=2N , 所以行号不变,列号加上len
(x,y)->(x,y+len)
区域2: 将原城市向右平移N-1级城市的边长,再向下平移N-1级城市的边长 所以行号和列号均加上len
(x,y)->(x+len,y+len).
区域3: 将原城市逆时针旋转90度,在水平翻转,以左上角为原点逆时针旋转
(x,y)->(y,-x)
水平翻转:
(y,-x)->(-y,-x)
要将其挪到左下角的位置,由于行号和列号都是从0开始
(-y,-x)->(-y+2*len-1,-x+len-1)
代码
#include<iostream>
#include<cmath>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> pll;
pll calc(LL N,LL M)//N为城市等级,M为该等级对应的编号
{
if(N==0) return {0,0};
//上一级城市的边长和房屋数量
LL len=1ll<<(N-1);
LL count=1ll<<(2*N-2);
pll pos=calc(N-1,M%count);//计算上一级城市
LL x=pos.first, y=pos.second;
LL z=M/count;//确定该编号在4块N-1级中的哪一块
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 n;//数据组数
cin>>n;
while(n--)
{
LL N,A,B;
cin>>N>>A>>B;
pll ac=calc(N,A-1);
pll bc=calc(N,B-1);//从0开始编号
LL x=ac.first-bc.first;
LL y=ac.second-bc.second;
double dis=sqrt(double((x*x+y*y)))*10;
printf("%.0lf\n",dis);
}
}