[COCI2017-2018#5] Spirale

前言

祭手博客第二篇~~~

话说这道题是真的冤屈: R E RE RE,将空间从 55 55 55改到 100 100 100 A A A了 QwQ

为什么这 20 20 20分不能加上去哇哇哇哇哇!!QAQ

题目

题目描述

S t j e p a n Stjepan Stjepan经常和他的朋友们一起在 Z a g r e b Zagreb Zagreb的一家酒吧玩。然而, S t j e p a n Stjepan Stjepan有时会喝过多的苏打水,里面的糖会让他头晕,比如昨晚就是一个例子。而当他头晕时,脑海中始终会拥有相同的场景,这个场景是一些数字螺旋的涂鸦,但他不能完全记住这些图像的样子,但可以描述它们。

S t j e p a n Stjepan Stjepan回忆说,这个图形是一个表格,由 N N N M M M列的数字组成。此外,这个表格中还有 K K K个螺旋线,每个螺旋线的起点是已知的,以及它的移动方向,可以是顺时针或逆时针。螺旋通过以下方式进行:

1、最初,表格是空的,每个螺旋都在自己的初始位置。

2、随后的每一步,每个螺旋都会移动到自己的下一个位置。如果这个螺旋会离开表格边界,但也会在后面返回。

3、在完成 1 0 100 10^{100} 10100个步骤后,对于每个表格中的数字,是其中一个螺旋到达这个表格最早的位置。

顺逆如图: 1逆2顺
在这里插入图片描述

输入格式

第一行输入三个数字 N N N 1 ≤ N ≤ 50 1≤N≤50 1N50), M M M 1 ≤ M ≤ 50 1≤M≤50 1M50), K K K 1 ≤ K ≤ N ∗ M 1≤K≤N*M 1KNM

接下来 K K K行,每行输入 3 3 3个数字,前两个数字表示螺旋的起始坐标(表格左上角坐标为( 1 , 1 1,1 1,1)),第三个数字表示螺旋的旋转方向,如果第三个数字是 0 0 0,表示是顺时针旋转,如果是1,表示是逆时针旋转。

输出格式

输出这个 N N N M M M列的表格中经过螺旋的答案。题目保证螺旋的步骤不会超过 1 0 100 10^{100} 10100

样例

样例输入1

3 3 1
2 2 0

样例输出1

9 2 3
8 1 4
7 6 5

样例输入2

3 3 1
2 2 1

样例输出2

3 2 9
4 1 8
5 6 7

样例输入3

3 3 2
1 1 0
1 2 0

样例输出3

1 1 4
6 5 5
19 18 17

解析

这道题开始一看到 1 0 100 10^{100} 10100着实吓了一跳,而且这个螺旋可以旋到外面去,这确实虚得很。。。

因此就开始推情况,将 3 ∗ 3 3*3 33的图顺时针逆时针都推了一下,一开始就成功得出了一个结论,这个螺旋线不可能超过 4 ∗ n ∗ n 4*n*n 4nn个。当然我不知道这对不对,因为推着推着就发现,其实这个螺旋线的边长最多即为它的出发点离这个矩阵的距离*2+1。

也就是说如图:
在这里插入图片描述
在这个图中,螺旋线的起点是这个阴影点,那么如果要让它笼罩整个矩阵的话,肯定它的一半的边长是这么大:
在这里插入图片描述
在这个图上,这个螺旋线最坏的情况跑成的矩阵如图所示,即它的边长的一半就是这个点离四条边的最长距离,然后再加上这个点,总共边长即为 d i s ∗ 2 + 1 dis*2+1 dis2+1

这么推完后这个题的难点基本就没了,剩下的就是简单的二维数组基本操作了,当然要注意的是控制下标的变量不能越界,不然也会 R E RE RE

参考代码

#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <queue>
#include <stack>
#include <cstring>
#include <iostream>
using namespace std;
#define reg register
#define LL long long
#define INF 0x3f3f3f3f

template<typename T>
void re (T &x){
    x = 0;
    int f = 1;
    char c = getchar ();
    while (c < '0' || c > '9'){
        if (c == '-') f = -1;
        c = getchar ();
    }
    while (c >= '0' && c <= '9'){
        x = (x << 1) + (x << 3) + c - 48;
        c = getchar ();
    }
    x *= f;
}

template<typename T>
void pr (T x){
    if (x < 0){
        putchar ('-');
        x = ~x + 1;
    }
    if (x / 10) pr (x / 10);
    putchar (x % 10 + 48);
}

int n, m, k, a[100][100];

int main (){
    re (n); re (m); re (k);
    memset (a, INF, sizeof (a));
    while (k --){
        int xx, yy, ty, num, tot = 0, cnt = 1;
        re (xx); re (yy); re (ty);
        a[xx][yy] = min (a[xx][yy], num = 1);
        tot = max (tot, n - xx);
        tot = max (tot, m - yy);
        tot = max (tot, xx - 1);
        tot = max (tot, yy - 1);
        tot = (tot * 2 + 1) * (tot * 2 + 1);
        //if (xx - 1 > 0) a[xx - 1][yy] = min (a[xx - 1][yy], num = 2);
        if (ty == 1){
            int x = xx, y = yy;
            int flag = 0;
            while (num < tot){
                int tmp = 1; flag ++;
                if (flag & 1) cnt ++;
                while (tmp < cnt && num < tot){
                    tmp ++; num ++; x --;
                    if (x > 0 && y > 0 && y <= m) a[x][y] = min (a[x][y], num);
                }
                tmp = 1; flag ++;
                if (flag & 1) cnt ++;
                while (tmp < cnt && num < tot){
                    tmp ++; num ++; y --;
                    if (x > 0 && y > 0 && x <= n) a[x][y] = min (a[x][y], num);
                }
                tmp = 1; flag ++;
                if (flag & 1) cnt ++;
                while (tmp < cnt && num < tot){
                    tmp ++; num ++; x ++;
                    if (x <= n && x > 0 && y > 0 && y <= m) a[x][y] = min (a[x][y], num);
                }
                tmp = 1; flag ++;
                if (flag & 1) cnt ++;
                while (tmp < cnt && num < tot){
                    tmp ++; num ++; y ++;
                    if (x > 0 && y > 0 && y <= m && x <= n) a[x][y] = min (a[x][y], num);
                }
            }
        }
        else{
            int x = xx, y = yy;
            int flag = 0;
            while (num < tot){
                int tmp = 1; flag ++;
                if (flag & 1) cnt ++;
                while (tmp < cnt && num < tot){
                    tmp ++; num ++; x --;
                    if (x > 0 && y > 0) a[x][y] = min (a[x][y], num);
                }
                tmp = 1; flag ++;
                if (flag & 1) cnt ++;
                while (tmp < cnt && num < tot){
                    tmp ++; num ++; y ++;
                    if (x > 0 && y > 0 && y <= m) a[x][y] = min (a[x][y], num);
                }
                tmp = 1; flag ++;
                if (flag & 1) cnt ++;
                while (tmp < cnt && num < tot){
                    tmp ++; num ++; x ++;
                    if (x > 0 && y > 0 && x <= n) a[x][y] = min (a[x][y], num);
                }
                tmp = 1; flag ++;
                if (flag & 1) cnt ++;
                while (tmp < cnt && num < tot){
                    tmp ++; num ++; y --;
                    if (x > 0 && y > 0) a[x][y] = min (a[x][y], num);
                }
            }
        }
    }
    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= m; j++){
            pr (a[i][j]);
            putchar (' ');
        }
        putchar (10);
    }
    return 0;
}

话说为什么听他们说好像直接大模拟也能过??不知道怎么搞的。。。

毕竟我不知道怎么判断整个矩阵到底填充完没有。。。而且就算填充完了也不一定是最小的,如果说直接模拟 2 100 2^{100} 2100那也太恐怖了吧, L L LL LL都没这么大、、、

果然我就是个蒟蒻 身边全是苣佬内心很受伤啊QwQ

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值