题目传送门:http://poj.org/problem?id=3889
感谢大雪菜大神bilibili上的讲解和李煜东大神书本的引导。
题面大概意思是:
给你一个原始的分形图,t组数据,对于每组数据,输入3个数n,h,o (n为在第n级,h,o为两个房子的编号),求在第n级情况下,编号为h和o的两个点之间的距离*10为多少。
其中,第n级分形图形成规则如下:
- 首先先在右下角和右上角复制一遍n-1情况下的分形图
- 然后将n-1情况下的分形图顺时针旋转90度,放到左上角
- 最后将n-1情况下的分形图逆时针旋转90度 ,放到左下角
编号是从左上角那个点开始计1,沿着道路计数。
分析:
这是著名的通过一定规律无限包含自身的分形图。为了计算方便,我们将题目中房屋编号从0开始编号,那么S与D也都减掉1.
大体思路:设calc(n,m)求编号为m的房屋编号在n级城市中的坐标位置,那么距离是:calc(n,s-1) 与 calc(n,d-1)的距离。
从n(n > 1)级城市由四座n-1级城市组成,其中:
1.左上的n-1级城市由城市结构顺时针旋转90度,从编号的顺序看,该结构还做水平翻转,坐标转换至n级时如下图。
2与3.右上和右下和原始城市结构一样,坐标转换至n级时如下图。
4.左下的n-1级城市由城市结构逆时针旋转90度,从编号的顺序看,该结构也做了水平翻转。
旋转坐标的变化可通过公式:
(设len = 2(n-1))当旋转角度是逆时针90度时,也就是顺时针270度时,(x,y)->(y, -x),然后再进行水平翻转,(y,-x)->(-y,-x)。然后再将图形平移到n级图形的左下角,在格子上的坐标变化是,水平方向增加len - 1个位置,垂直方向增加2len - 1个位置。因此坐标(x,y)按照规则转移到了(2len-1-y,len-1-x).
注意:n-1级格子里拥有的房子数量是cnt = 22n /4,即22n-2.
当前编号m在N级格子的哪个方位是:m / cnt.
当前编号m在n-1级格子里的编号是: m %cnt;
详细代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
pair<LL,LL> calc(LL n, LL m){
if(n == 0) return make_pair(0,0);
LL len = 1ll << (n-1) , cnt = 1ll << (2*n - 2);
pair<LL,LL> pos = calc( n-1, m%cnt);
LL x = pos.first , y = pos.second;
LL z = m / cnt;//z的值代表这n-1级的(x,y)在n级城市中的方位。
if ( z == 0 ) return make_pair(y , x); //左上
if ( z == 1 ) return make_pair(x, y + len);//右上
if ( z == 2 ) return make_pair(x+len, y + len);//右下
return make_pair(2*len-1-y, len - 1- x);// 左下
}
int main(){
int T;
cin >> T;
while(T--){
LL N,A,B;
cin >> N >> A >> B;
pair<LL,LL> s = calc(N, A - 1);
pair<LL,LL> d = calc(N, B - 1);
LL ax = s.first - d.first,ay = s.second - d.second;
cout <<fixed << setprecision(0) << sqrt(ax * ax + ay * ay)*10<< endl;
}
return 0;
}