算法竞赛进阶指南, p 18, 代码抄 b站 大雪莱的
本题要点:
1、递归,N 级的图,可以分为 4 个 N - 1 级图
PLL calc(LL n, LL m) //计算 n 级图,第m点的坐标
转换为, 求出 m点位于哪个子级图中(左上,右上,右下,左下)
PLL pos = calc(n - 1, m % cnt); //这一步,求出 m 点在子级图的坐标 (x1, y1)
但是,要把 (x1, y1) 转化为 m 点在 当前 N 级图的坐标 (x0, y0)
2、 坐标转换
a)子图 在左上
在子图(N - 1 级图), 先顺时针转90度,变为 (y1, 2^(n - 1) - x1 - 1)
再水平翻转(坐标1不变,坐标2关于边的中心对称), 变为(y1, x1)
也就是 x0 = y1, y0 = x1
b)子图 在右上
平移关系
x0 = x1, y0 = y1 + 2^(n - 1)
c)子图 在右下
平移关系
x0 = x1 + 2^(n - 1), y0 = y1 + 2^(n - 1)
d)子图 在左下
在子图(N - 1 级图), 先逆时针转90度再水平翻转,变为 (2^(n - 1) - y1 - 1, 2^(n - 1) - x1 - 1)
行号加上 2^(n - 1), 变为了 (2^n - y1 - 1, 2^(n - 1) - x1 - 1)
也就是 x0 = 2^n - y1 - 1, y0 = 2^(n - 1) - x1 - 1
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;typedef long long LL;
typedef pair<LL, LL> PLL;PLL calc(LL n, LL m) //计算 n 级图,第m点的坐标
{
if(0 == n) //如果是0 级图,坐标只能是 (0, 0){
return make_pair(0, 0);}LL len = 1ll << (n - 1); LL cnt = 1ll << (2 * n - 2);PLL pos = calc(n - 1, m % cnt);LL x = pos.first, y = pos.second;LL z = m / cnt;if(0 == z) //左上{
return make_pair(y, x);}if(1 == z) //右上{
return make_pair(x, y + len);}if(2 == z) //右下{
return make_pair(x + len, y + len);}//左下return make_pair(2 * len - y - 1, len - x - 1);
}int main()
{
int Test;scanf("%d", &Test);while(Test--){
LL N, A, B;scanf("%lld%lld%lld", &N, &A, &B);PLL ac = calc(N, A - 1);PLL bc = calc(N, B - 1);double x = ac.first - bc.first, y = ac.second - bc.second;printf("%.0f\n", sqrt(x * x + y * y) * 10); //这里用 %lf 输出,poj 会 wa}return 0;
}/* 3 1 1 2 2 16 1 3 4 33 *//* 10 30 50 */