「2019牛客多校第十场E」Hilbert Sort【思维】

「2019牛客多校第十场E」Hilbert Sort【思维】_第1张图片

题意

  • 就是上面那个图,边长 2 k × 2 k 2^k\times 2^k 2k×2k的矩形是由边长为 2 k − 1 × 2 k − 1 2^{k-1}\times 2^{k-1} 2k1×2k1旋转阔者平移然后拼接而来,每个图从左上角进入,右上角出去,从入口进去一次访问给定的一些节点,问访问顺序

题解

  • 之所以给这题的 t a g tag tag是思维因为如果直接蛮写【记录入口出口分8种情况玩大模拟,队友就是这么干的】也是可以过的,但是可以简便一点做,赛后简单推了一下,首先显然可以求出每个点的时间戳,排序输出就行了,求时间戳的时候,讨论 [ x , y ] [x,y] [x,y]在当前正方形的哪一块【分四块】然后这一小块其实与前一大块是相同大小的【前一大块就是指当前这一大块的直接来源】,然后考虑怎么把这个坐标映射到前一大块,然后就能求解更小的问题了,显然做个对称点就行了
  • 需要一点简单的高中知识:点 [ x 0 , y 0 ] [x_0,y_0] [x0,y0],关于 y = − x + b y=-x+b y=x+b的对称点为 [ b − y 0 , b − x 0 ] [b-y_0,b-x_0] [by0,bx0],关于 y = x + b y=x+b y=x+b的对称点为 [ y 0 − b , x 0 + b ] [y_0-b,x_0+b] [y0b,x0+b]

代码

#include

using namespace std;

struct node{
    int x,y;long long step;
    friend bool operator<(const node&a,const node&b) {
        return a.step<b.step;
    }
}a[1000005];
int n,k;

long long dfs(int x,int y,int k)
{
    if(k==0) return 1;
    int siz=(1<<(k-1));
    if(x<=siz) {
        if(y<=siz) return dfs(y,x,k-1);
        return 3LL*siz*siz+dfs(2*siz+1-y,siz+1-x,k-1);
    }else{
        if(y<=siz) return 1LL*siz*siz+dfs(x-siz,y,k-1);
        return 2LL*siz*siz+dfs(x-siz,y-siz,k-1);
    }
}

int main()
{
    scanf("%d %d",&n,&k);
    for(int i=1;i<=n;i++) {
        scanf("%d %d",&a[i].x,&a[i].y);
        a[i].step=dfs(a[i].x,a[i].y,k);
    }
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++) printf("%d %d\n",a[i].x,a[i].y);
}

你可能感兴趣的:(思维)