首页 > 其他分享 >King's Tour 题解

King's Tour 题解

时间:2023-10-13 16:01:46浏览次数:30  
标签:King x1 int 题解 walk x2 Tour y1 y2

King's Tour

题面大意

在 \(n\times m\) 的网格中构造一种从 \((1,1)\) 走到 \((a,b)\) 的方案,要求经过所有格子恰好一次,格子之间八联通。

思路分析

模拟赛题,赛时写了一个半小时过了(

思路不是很复杂,但是需要一些分类讨论。


  • 引理:对于任意大小的矩形,一定存在从左上走到右下的方案。

  • 证明:

若长宽中有一个是奇数,那么我们可以按照如下方案构造:

否则,我们可以按照如下方案构造:


那么同理,我们只需要将矩形翻转就可以得到从矩形一个角走到对角的方案。

walk(x1,y1,x2,y2) 表示输出从 \((x_1,y_1)\) 走到 \((x_2,y_2)\),填满以 \((x_1,y_1)\) 和 \((x_2,y_2)\) 作为对角线的矩形的方案。

而当我们考虑从 \((1,1)\) 走到 \((a,b)\) 时,我们进行分类讨论,下面是图示和代码实现:

(蓝色边表示用引理的方案填满整个矩形,绿色边表示实际走的边。)

  • \(a=n,b=m\):

walk(1, 1, a, b)
  • \(a=1,b=m\):

walk(1, 1, n, m - 1);
walk(n, m, a, b);
  • \(a=n,b=1\):

walk(1, 1, n - 1, m);
walk(n, m, a, b);
  • \(a=1,b\not =m\):

walk(1, 1, n, b - 1);
walk(n, b, 2, m);
walk(1, m, a, b);
  • \(b=1,a\not =n\):

walk(1, 1, a - 1, m);
walk(a, m, n, 2);
walk(n, 1, a, b);
  • \(a=n,b\not =1\):

walk(1, 1, n, b - 1);
walk(n - 1, b, 1, b);
walk(1, b + 1, n - 1, m);
walk(n, m, a, b);
  • \(b=m,a\not =1\):

walk(1, 1, a - 1, m);
walk(a, m - 1, n - 1, 1);
walk(n, 1, n, m);
walk(n - 1, m, a, b);
  • \(a\in[2,n-1],b\in[2,m-1]\):

walk(1, 1, a - 1, m);
walk(a, m, n, b + 1);
walk(n, b, a + 1, 1);
walk(a, 1, a, b);

那么这题就愉快的结束了,时间复杂度显然是 \(O(n^2)\)。

代码

(109 行,3.5k)

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>

using namespace std;
const int N = 200200;
#define inf 0x3f3f3f3f

int n, m, a, b;

namespace SOL{
    void walk(int x1, int y1, int x2, int y2){
        int dir;
        if (x1 <= x2 && y1 <= y2) dir = 1;
        if (x1 > x2 && y1 <= y2) dir = 3;
        if (x1 <= x2 && y1 > y2) dir = 2;
        if (x1 > x2 && y1 > y2) dir = 4;
        if (x1 > x2) swap(x1, x2);
        if (y1 > y2) swap(y1, y2);
        int n = x2 - x1 + 1, m = y2 - y1 + 1;
        vector <pair<int, int>> v; 
        if ((n & 1) || (m & 1)) {
            if (n & 1) {
                int x = 1, y = 0, d = 1;
                for (int i = 1; i <= n * m; i ++) {
                    y += d;
                    if (y == m + 1) y = m, x ++, d = -d;
                    if (y == 0)  y = 1, x ++, d = -d;
                    v.push_back({x, y});
                }
            }
            else {
                int x = 0, y = 1, d = 1;
                for (int i = 1; i <= n * m; i ++) {
                    x += d;
                    if (x == n + 1) x = n, y ++, d = -d;
                    if (x == 0)  x = 1, y ++, d = -d;
                    v.push_back({x, y});
                }
            }
        }
        else {
            int x = 1, y = 0, d = 1;
            for (int i = 1; i <= (n - 2) * m; i ++) {
                y += d;
                if (y == m + 1) y = m, x ++, d = -d;
                if (y == 0)  y = 1, x ++, d = -d;
                v.push_back({x, y});
            }
            for (int i = 1; i <= m; i ++) {
                v.push_back({n - 1, i});
                v.push_back({n, i});
            } 
        }
        if (dir == 2) for (auto &it : v) it.second = m - it.second + 1;
        if (dir == 3) for (auto &it : v) it.first = n - it.first + 1;
        if (dir == 4) for (auto &it : v) it.first = n - it.first + 1, it.second = m - it.second + 1;
        for (auto it : v) cout << it.first + x1 - 1 << ' ' << it.second + y1 - 1 << '\n';
    }
    void work(){
        if (a == n && b == m) {
            walk(1, 1, n, m);
        }
        else if (a == n && b == 1) {
            walk(1, 1, n - 1, m);
            walk(n, m, a, b);
        }
        else if (a == 1 && b == m) {
            walk(1, 1, n, m - 1);
            walk(n, m, a, b);
        }
        else if (a == 1) {
            walk(1, 1, n, b - 1);
            walk(n, b, 2, m);
            walk(1, m, a, b);
        } 
        else if (b == m) {
            walk(1, 1, a - 1, m);
            walk(a, m - 1, n - 1, 1);
            walk(n, 1, n, m);
            walk(n - 1, m, a, b);
        }
        else if (a == n) {
            walk(1, 1, n, b - 1);
            walk(n - 1, b, 1, b);
            walk(1, b + 1, n - 1, m);
            walk(n, m, a, b);
        }
        else if (b == 1) {
            walk(1, 1, a - 1, m);
            walk(a, m, n, 2);
            walk(n, 1, a, b);
        }
        else {
            walk(1, 1, a - 1, m);
            walk(a, m, n, b + 1);
            walk(n, b, a + 1, 1);
            walk(a, 1, a, b);
        }
    }
}

int main(){
    scanf("%d %d %d %d", &n, &m, &a, &b);
    return SOL::work(), 0;
}

标签:King,x1,int,题解,walk,x2,Tour,y1,y2
From: https://www.cnblogs.com/TKXZ133/p/17762357.html

相关文章

  • 【多校联考NOIP#3】比赛复盘 && 题解
    A.卡牌这次比赛,一道签到题都没有。本来以为是线段树上二分。就类似于花神的数论题那道,刚开始暴力修改(修改到线段树的每一个叶子节点),然后由于boss的attack在不断增加,到了\(Att_i>=hp_j\)的时候,\(j\)这个牌顶多打一次,如果一个区间的\(max\)都小于boss的攻击力了,那么就不......
  • CF1886A Sum of Three 题解
    Question给定一个正整数N,我们需要找三个不同的整数x,y,z,使得N=x+y+z,其中下x,y,z不能被三整除solution我们把N%3会有一些余数,我们针对余数来讨论,其中我们只关注xyz的余数如果余数为0那么也就可能是1+1+1,或者2+2+2,但是考虑到xyz不同,所以如果\(xyz\%3\)相同的话,\(xyz/3\)......
  • 题解 P2188 小Z的 k 紧凑数
    题目描述小Z在草稿纸上列出了很多数,他觉得相邻两位数字差的绝对值不超过\(k\)的整数特别奇特,称其为\(k\)紧凑数。现在小Z想知道\([l,r]\)内有多少个\(k\)紧凑数,希望你帮帮他。具体思路首先,要求数的个数,自然想到数位dp。然后可以用容斥原理拆询问。\[ans=\sum_{......
  • CF1886C Decreasing String 题解
    题面\(S_n\)由\(S_{n-1}\)去掉一个字母得到,\(S=S_1+S_2+...+S_n\)给定\(S_1\)求\(S\)的第\(N\)位solution我们先考虑怎样去字母能保持字典序最小显然,我们发现如果一个字母比前面那个字母小,那么我们就要删除前面那个字母也就是我们要删除一些字母,保持剩余的字母单调......
  • CF1886B Fear of the Dark 题解
    QuestionMonocarp在一个二维平面上,他的初始点在\(O=(0,0)\),他需要到\(P(P_x,P_y)\)不幸的是,他能走的范围在两个圆内,我们给出了两个圆的坐标\(A=(A_x,A_y)\),\(B=(B_x,B_y)\)两个圆的半径相同,我们需要找到最小的半径让Monocarp能同\(O\)走到\(P\)Solution这题可以......
  • Docker 安装Skywalking
    安装SKYWALKING可以采用H2存储数据或者ELASTICSEARCH存储,我们这里采用ELASTICSEARCH存储,采用OAP处理数据,并基于SKYWALKINGUI展示数据,所以安装的服务有多个安装ElasticSearch7安装kibana安装Skywalking-OAP安装SkywalkingUI参考地址https://skywalking.apache.org/downl......
  • Skywalking APM监控系列(二、Mysql、Linux服务器与前端JS接入Skywalking监听)
    前言上篇我们介绍了Skywalking的基本概念与如何接入.NetCore项目,感兴趣可以去看看:SkywalkingAPM监控系列(一丶.NET5.0+接入Skywalking监听)本篇我们主要讲解一下Skywalking如何接入mysql数据库监听与Linux服务器的监听其实从Skywalking设计之初应该只是单独的链路跟踪,发......
  • 网络规划设计师真题解析--TCP慢启动拥塞避免机制取值问题
    若TCP最大段长为1000字节,在建立连接后慢启动,第1轮次发送了1个段并收到了应答,应答报文中window字段为5000字节,此时还能发送(25)字节。(2019年)(25)A.1000    B.2000     C.3000     D.5000答案:B解析:假如TCP最大段长为1000字节,在建立连接后慢启动第1轮发送了1个段......
  • [APIO2019] 路灯 题解
    LG5445把询问\(x,y\)看作平面上的点记当前时刻\(t\),\(l\)是与\(i\)连通的最左端,\(r\)是与\(i+1\)连通的最右端,可以通过set维护断边找到连边\((i,i+1)\)时\(x\in[l,i],y\in[i+1,r]\)连通了,考虑贡献提前计算,矩形\(+(q-t)\)。断边时同理\(-(q-t)\)剩下的问题是......
  • CF963B Destruction of a Tree 题解
    CF963BDestructionofaTree题解  洛谷题目链接  这里提供一个较为朴素的DP想法。题意简述  给定一棵树,节点个数不超过\(2\times10^5\),每次可以删掉度数为偶数的点。问最后能不能删完;能删完给出删除方案。思路分析  首先可以随便选一个点作为根。  其次,......