hilbert
hilbert |
难度级别: A; 编程语言:不限;运行时间限制:1000ms; 运行空间限制:131072KB; 代码长度限制:102400B |
试题描述
|
图1为1阶Hilbert曲线,它由3条长度为1的线段构成;
|
输入
|
输入文件包含多组测试数据。
第一行,一个整数T,表示测试数据的组数。 接下来的T行,每行五个整数,N、x0、y0、x1、y1。 |
输出
|
T行,每行一个整数,其中第i行的整数表示第i组测试数据中沿着Hilbert曲线从(x0,y0)走到(x1,y1)需要走的路线长度。
|
输入示例
|
3
1 0 1 1 0 2 2 2 0 1 3 1 5 4 2 |
输出示例
|
2
5 36 |
其他说明
|
本题共2组测试数据。
测试点1:1<=N<=8; 测试点2:1<=N<=30。 对于全部的数据,1<=T<=500。 |
分治法,类似棋盘覆盖,先将问题转化成前缀减法,每次计算先确定是那个区域,再递归调用。
注意棋盘有4种形态,可以通过坐标变换转化成2种。
只是代码有些难写
#include<cstdio> #include<cctype> #include<stack> #include<queue> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i!=-1;i=next[i]) using namespace std; inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } typedef long long ll; ll solve(int n,int x,int y,int inv) { if(n==1) { if(inv) return x==1&&y==0?3:x+y; else return x==0&&y==1?3:x+y; } ll N=(1<<n); if(inv) { if(x<N/2&&y<N/2) return solve(n-1,x,y,inv^1); if(x<N/2&&y>=N/2) return solve(n-1,x,y-(N/2),inv)+(N*N/4); if(x>=N/2&&y>=N/2) return solve(n-1,x-(N/2),y-(N/2),inv)+(N*N/4)*2; return solve(n-1,N-x-1,(N/2)-y-1,inv^1)+(N*N/4)*3; } else { if(x<N/2&&y<N/2) return solve(n-1,x,y,inv^1); if(x<N/2&&y>=N/2) return solve(n-1,(N/2)-x-1,N-y-1,inv^1)+(N*N/4)*3; if(x>=N/2&&y>=N/2) return solve(n-1,x-(N/2),y-(N/2),inv)+(N*N/4)*2; return solve(n-1,x-(N/2),y,inv)+(N*N/4); } } int main() { int T=read(); while(T--) { int n=read(),x0=read(),y0=read(),x1=read(),y1=read(); printf("%lld\n",abs(solve(n,x0,y0,1)-solve(n,x1,y1,1))); } return 0; }