【算法竞赛进阶指南】分形之城

题目链接

思路

把左上角的坐标看做 \((0 , 0)\),右上角的坐标为 \((0,2^n-1)\),左下角的坐标为 \((2^n-1,0)\),右下角坐标为 \((2^n-1,2^n-1)\)

街区的标号也从 \(0\) 开始。

现在对于给定的两个距离,我们要分别求出他们的坐标。

现在给出等级为 \(2\),距离为 \(10\),如何求坐标呢?

等级为 \(1\) 的城市中有 \(4\) 座街区,通过 \(10/4 = 2\),可以知道这个街区在 等级为 \(2\) 的右下角,即图中 \(4\) 部分。

这时如果可以求出它在 \(4\) 中的坐标,横纵坐标都加上 \(2\),就得到了它在等级为 \(2\) 的城市中的坐标。

求其在 \(4\) 中的坐标可以转化为 求在等级 \(1\) 中,距离为 \(10\%4\) 的坐标 (因为 \(4\) 部分是直接复制的等级为 \(1\) 的城市)

这样问题就可以递归解决。

定义函数 \(cal(N,M) 表示求在 N 级城市中,距离起点距离为 M 的坐标\)

\(cal(N,M)\) 时,\(N-1\) 级城市有 \(2^{2*N-2}\) 座街区,先递归求解 \(cal(N-1,M mod\ 2^{2*N-2})\)

注意这时还要进行坐标变换:\(4\)部分没有进行是因为它是直接从 \(N-1\) 级城市复制得到的。

假如在 \(1\) 部分,通过观察可以知道,\(1\) 部分是 \(N-1\) 级城市 顺时针旋转,然后水平翻转得到的。

如果在 \(2\) 部分,也不需要变换

如果在 \(3\) 部分,先逆时针旋转90度,然后水平翻转。

如果在 \(4\) 部分,不需要变换。

这时已经得到该点在 \(N-1\) 级城市中的坐标。

那么针对这 \(4\) 部分的点,横纵坐标加上不同的值即可。

\(1\) 部分不需要加

\(2\) 部分纵坐标加上 \(N-1\) 级城市的边长

\(3\) 部分横坐标加上 \(N-1\) 级城市的边长

\(4\) 部分横纵坐标均加上 \(N-1\) 级城市的边长

代码

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mod = 1e9 + 7;
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int N = 2e5 + 10;

pair<ll, ll> cal(ll n, ll now)
{
    if (n == 0)
        return { 0, 0 };
    ll len = 1LL << (n - 1), cnt = 1LL << (2 * n - 2);
    pair<ll, ll> pre = cal(n - 1, now % cnt);
    ll x = pre.first, y = pre.second;
    int tmp = now / cnt;
    if (tmp == 0) {
        return { y, x };
    } else if (tmp == 1) {
        return { x, y + len };
    } else if (tmp == 2) {
        return { x + len, y + len };
    } else {
        return { 2 * len - y - 1, len - x - 1 };
    }
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--) {
        ll n, a, b;
        scanf("%lld%lld%lld", &n, &a, &b);
        pair<ll, ll> aga = cal(n, a - 1);
        pair<ll, ll> en = cal(n, b - 1);
        double dis = sqrt(pow((aga.first - en.first) * 10, 2) + pow((aga.second - en.second) * 10, 2));
        printf("%.0lf\n", dis);
    }
    return 0;
}
posted @ 2020-11-25 09:48  Valk3  阅读(197)  评论(0编辑  收藏  举报