【题解】AcWing 98.分形之城

AcWing 98.分形之城

题目描述

城市的规划在城市建设中是个大问题。

不幸的是,很多城市在开始建设的时候并没有很好的规划,城市规模扩大之后规划不合理的问题就开始显现。

而这座名为 Fractal 的城市设想了这样的一个规划方案,如下图所示:

在这里插入图片描述
当城区规模扩大之后,Fractal 的解决方案是把和原来城区结构一样的区域按照图中的方式建设在城市周围,提升城市的等级。

对于任意等级的城市,我们把正方形街区从左上角开始按照道路标号。

虽然这个方案很烂,Fractal 规划部门的人员还是想知道,如果城市发展到了等级 N N N,编号为 A A A B B B 的两个街区的直线距离是多少。

街区的距离指的是街区的中心点之间的距离,每个街区都是边长为 10 10 10 米的正方形。

输入格式

第一行输入正整数 n n n,表示测试数据的数目。

以下 n n n 行,输入 n n n 组测试数据,每组一行。

每组数据包括三个整数 N , A , B N,A,B N,A,B,表示城市等级以及两个街区的编号,整数之间用空格隔开。

输出格式

一共输出 n n n 行数据,每行对应一组测试数据的输出结果,结果四舍五入到整数。

数据范围

1 ≤ N ≤ 31 1≤N≤31 1N31,
1 ≤ A , B ≤ 2 2 N 1≤A,B≤2^{2N} 1A,B22N,
1 ≤ n ≤ 1000 1≤n≤1000 1n1000

输入样例:

3 
1 1 2 
2 16 1 
3 4 33 

输出样例:

10 
30 
50 

题目分析

为了方便计算,我们不妨将所有街区的编号减一。对于每个街区,我们需要通过其编号求出坐标位置,从而计算两个街区间的直线距离

设编号为 M M M 的街区在 N N N 级城市中的位置为 c a l c ( N , M ) calc(N,M) calc(N,M),考虑如何通过一个街区的编号求坐标:

  1. 递归求出其在 N − 1 N-1 N1 级城市中的位置 c a l c ( N − 1 , M   m o d   2 2 N − 2 ) = ( x , y ) calc(N-1,M\ mod\ 2^{2N-2})=(x,y) calc(N1,M mod 22N2)=(x,y),其中 x x x 为行数, y y y 为列数
  2. 再根据 M   m o d   2 2 N − 2 M\ mod\ 2^{2N-2} M mod 22N2 的大小,可以确定其属于四座 N − 1 N-1 N1 的城市中的哪一座
  3. 若处于左上角,则先顺时针旋转 90 ° 90° 90°,坐标变为 ( y , 2 N − 1 − x − 1 ) (y,2^{N-1}-x-1) (y,2N1x1),再水平翻转,坐标变为 ( y , x ) (y,x) (y,x)
  4. 若处于右上角,坐标变为 ( x , y + 2 N − 1 ) (x,y+2^{N-1}) (x,y+2N1)
  5. 若处于右下角,坐标变为 ( x + 2 N − 1 , y + 2 N − 1 ) (x+2^{N-1},y+2^{N-1}) (x+2N1,y+2N1)
  6. 若处于左下角,则先逆时针旋转 90 ° 90° 90°,坐标变为 ( 2 N − 1 − y − 1 , x ) (2^{N-1}-y-1,x) (2N1y1,x),再水平翻转,坐标变为 ( 2 N − 1 − y − 1 , 2 N − 1 − x − 1 ) (2^{N-1}-y-1,2^{N-1}-x-1) (2N1y1,2N1x1),最后行号加上 2 N − 1 2^{N-1} 2N1,得到 ( 2 N − y − 1 , 2 N − 1 − x − 1 ) (2^N-y-1,2^{N-1}-x-1) (2Ny1,2N1x1)

代码:

#include <cstdio>
#include <utility>
#include <cmath>
using namespace std;

typedef long long ll;
typedef pair <ll, ll> pll;

int t;
ll N, A, B, x, y;
pll a, b;

pll calc(ll n, ll m){
    
    
    if (!n) return {
    
    0, 0};
    ll len = 1ll << (n - 1), cnt = 1ll << (2 * n - 2);
    pll pos = calc(n - 1, m % cnt);
    ll x = pos.first, y = pos.second, z = m / cnt;
    if (z == 0) return {
    
    y, x};
    if (z == 1) return {
    
    x, y + len};
    if (z == 2) return {
    
    x + len, y + len};
    return {
    
    len * 2 - y - 1, len - x - 1};
}

int main(){
    
    
    scanf("%d", &t);
    while (t --){
    
    
        scanf("%lld%lld%lld", &N, &A, &B);
        a = calc(N, A - 1), b = calc(N, B - 1);
        x = a.first - b.first, y = a.second - b.second;
        double dis = sqrt(x * x + y * y);
        printf("%.0lf\n", 10 * dis);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/f4u4u4r/article/details/118061002
今日推荐