Problem
题目描述
城市的规划在城市建设中是个大问题。不幸的是,很多城市在开始建设的时候并没有很 好的规划,城市规模扩大之后规划不合理的问题就开始显现。而这座名为Fractal 的城市设 想了这样的一个规划方案,如下图所示:
当城区规模扩大之后,Fractal 的解决方案是把和原来城区结构一样的区域按照图中的方 式建设在城市周围,提升城市的等级。对于任意等级的城市,我们把正方形街区从左上角开 始按照道路标号。虽然这个方案很烂,Fractal 规划部门的人员还是想知道,如果城市发展到 了等级N,编号为A 和B 的两个街区的直线距离是多少。街区的距离指的是街区的中心点 之间的距离,每个街区都是边长为10 米的正方形。
Solution
只负责说大致方法不负责写推导过程。
我们发现对于每一个等级,其实就是由前一个等级的状态扩展而来的。那么我们可以通过找到状态与状态之间的关系来作为解决这个问题的突破口,也据此来用递归的当时实现求解。
对于每一个房屋,都可以归类为当前等级的4块中的一块,而且十分容易得知是当前块中第几大(可以用取模来搞)。这个区间第几大知道以后,例如第i大,和前一个等级的第i大作比较,通过坐标的之间的关系即可得到坐标。
具体的坐标变换是这样的(n−1级→n级):
- 左上区域:(x,y)→(y,x)
- 右上区域:(x,y)→(x,y+2n−1)
- 右下区域:(x,y)→(x+2n−1,y+2n−1)
- 左下区域:(x,y)→(2n−y+1,2n−1−x+1)
其实只要在草稿纸上面列出一堆数字找找规律就好了。
#include <iostream>
#include <cstdio>
#include <utility>
#include <cmath>
#define Pair pair<LL,LL>
#define make make_pair
#define x1 posA.first
#define x2 posB.first
#define y1 posA.second
#define y2 posB.second
#define LL long long
using namespace std;
Pair dfs(LL n,LL m)
{
if (n == 1)
{
if (m == 1) return make(1,1);
if (m == 2) return make(1,2);
if (m == 3) return make(2,2);
if (m == 4) return make(2,1);
}
LL cnt=pow(2,2*n-2),len=pow(2,n),len0=pow(2,n-1);
Pair last;
if (m <= cnt) last=dfs(n-1,m);
else if (m <= 2*cnt) last=dfs(n-1,m-cnt);
else if (m <= 3*cnt) last=dfs(n-1,m-cnt*2);
else if (m <= 4*cnt) last=dfs(n-1,m-cnt*3);
LL x=last.first,y=last.second;
if ((m-1)/cnt == 0) return make(y,x);
if ((m-1)/cnt == 1) return make(x,y+len0);
if ((m-1)/cnt == 2) return make(x+len0,y+len0);
if ((m-1)/cnt == 3) return make(len-y+1,len0-x+1);
}
int main(void)
{
freopen("fra.in","r",stdin);
freopen("fra.out","w",stdout);
LL T;
scanf("%lld",&T);
while (T --)
{
LL N,A,B;
scanf("%lld %lld %lld",&N,&A,&B);
Pair posA=dfs(N,A);
Pair posB=dfs(N,B);
printf("%.0lf\n",10*sqrt(1.0*(x1-x2)*(x1-x2) + 1.0*(y1-y2)*(y1-y2)));
}
return 0;
}