原题链接

思路

分形之城(分形)_坐标变换

我们可以通过题目上给出的图示看出,每一个等级的图是由前一个等级的图拼成的,拼接方式如图

分形之城(分形)_坐标轴_02

因此在求解一个图上某一点的编号时,我们需要确定他是属于哪一块的,再进行坐标变换。

同时为了方便确定,我们将所有点的编号从0开始,同时坐标轴也会从0,开始。

接下来我们看坐标变化,以下图为例(图确实是太丑了-_-)

分形之城(分形)_c++_03

我们假设要求的编号为a,则它位于哪个区域就是z=a/block,同时知道它在上一级(小的)中的编号p=a%block,同时因为经常用,所以将len=2^{n-1};

则,我们求出他在上一级中的坐标

\[(x,y)=get(n-1,p) \]

此时我们根据该点所在区域,来进行坐标转换

  1. 左上角,只需要只需要将坐标进行转换即可

    \[(x,y)=>(y,x) \]

  2. 右上角,只需要将y坐标增加len,即

    \[(x,y)=>(x,y+len) \]

  3. 右下角,只需将x,y坐标军增加len,即

    \[(x,y)=>(x+len,y+len) \]

  4. 左下角,稍微麻烦一些,画图进行理解

    分形之城(分形)_坐标转换_04

    我们从图中便可以很好地的理解,变换即为

    \[(x,y)=>(2*len-1-y,len-1-x) \]

  5. 注意边界,当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;
}