• 【题解】小澳的方阵


    题目

    题目来源:20200523 模拟赛 T1;(具体版权未知)。

    测试链接:咕咕咕

    题目背景

    小澳最近迷上了考古,他发现秦始皇的兵马俑布局十分有特点,热爱钻研的小澳打算在电脑上还原这个伟大的布局。

    题目描述

    他努力钻研,发现秦始皇布置兵马俑是有一定规律的。兵马俑阵总共有 (n)(m) 列,秦始皇在布置的时候每次会指定一行或一列,然后指定一个兵种,使得这一行或者这一列上全部放上这一个兵种。如果这一行上以前放过其它的兵种,那么他会拔掉以前的兵种改成现在他命令的兵种。

    小澳从秦朝的文献中找到了布置这个方阵的操作顺序,他希望你能告诉他布局完成后整个兵马俑阵是什么样子的。

    输入格式

    输入文件共 (q+1) 行。

    输入文件第 (1) 行包括三个正整数 (n)(m)(q),分别表示兵马俑阵的行数和列数,以及秦始皇总的操作数。

    接下来 (q) 行,每行三个正整数 (x)(y)(z)(x) 表示操作种类:

    • (x=1),表示给第 (y) 行((yle n))全部放上 (z) 这个兵种;
    • (x=2),则表示给第 (y) 列((yle m))全部放上 (z) 这个兵种。

    输出格式

    输出文件共 (n) 行,每行 (m) 个整数,分别用空格隔开。表示最后方阵上每个位置放的兵种,如果某个位置没有被操作过输出 (0)

    评测限制

    从 matrix.in 中读入,输出到 matrix.out。

    评测时间限制 (1000 extrm{ms}),空间限制 (256 extrm{MiB})

    数据范围与约定

    • 对于 (20\%) 的数据,(nmle 25)
    • 对于 (30\%) 的数据,(qle 2000)
    • 对于 (100\%) 的数据,(n,mle 1000)(nmle 10^5)(qle 10^6)

    分析

    题意是,对于一个矩阵,每一次给一行或一列赋值,后赋值的会覆盖前面赋值的。输出这个矩阵赋值后的结果。

    (30 exttt{pts})

    这就是一个简单的大暴力,每一次都赋值一遍即可。

    (100 exttt{pts})

    想到这一点,我们不妨看一看数据范围:(large{qle 10^6})。也就是说,会多次修改同一行或同一列。

    那么,我们每一次都赋值就非常慢,而且后面会被覆盖。那怎么办呢?

    我们不妨倒过来想:影响一个格子的兵种的因素是什么?显然是横竖分别赋值的兵种中较晚的一个。

    所以,有一个思路就非常自然:记录每一行和每一列最后修改的内容和时间。输出每一个格子的时候,检查横竖的最晚时间并输出对应兵种。

    事实上,这个做法就是正解。我们只需要在修改的时候打上「Lazy Tag」即可。复杂度 (Theta(nm+q)) 绰绰有余。

    Code

    这实际上就是一个不折不扣的模拟,所以代码量非常少。

    #include <cstdio>
    #include <cctype>
    using namespace std;
    
    const int max_n = 1000;
    struct lin
    {
    	int tim, val;
    };
    
    lin row[max_n] = {}, col[max_n] = {};
    
    inline int read()
    {
    	int ch = getchar(), t = 1, n = 0;
    	while (isspace(ch)) { ch = getchar(); }
    	if (ch == '-') { t = -1, ch = getchar(); }
    	while (isdigit(ch)) { n = n * 10 + ch - '0', ch = getchar(); }
    	return n * t;
    }
    
    int main()
    {
    	int n = read(), m = read(), q = read(), opt, id, tid;
    	
    	for (int i = 0; i < q; i++)
    	{
    		opt = read(), id = read() - 1, tid = read();
    
    		if (opt & 1)
    			row[id].tim = i + 1, row[id].val = tid;
    		else
    			col[id].tim = i + 1, col[id].val = tid;
    	}
    
    	for (int i = 0; i < n; i++)
    	{
    		for (int j = 0; j < m; j++)
    		{
    			if (row[i].tim > col[j].tim)
    				printf("%d ", row[i].val);
    			else
    				printf("%d ", col[j].val);
    		}
    
    		putchar('
    ');
    	}
    
    	return 0;
    }
    

    后记

    顺带一提,类似的题目还有很多,只不过方法有所不同。

    有一些利用了差分,加上线段树优化以后才能通过。而另一些甚至于要用二维线段树才能解决。

    所以,这种东西很难类比,因为接近的题目也不一定是相同的做法。

  • 相关阅读:
    计数和查找
    遍历
    top小火箭
    leetcode 字符串中的第一个唯一字符
    leetcode 颠倒整数
    leetcode 反转字符串
    leetcode 有效的数独
    leetcode 两数之和
    leetcode 移动零
    leetcode 加一
  • 原文地址:https://www.cnblogs.com/5ab-juruo/p/solution-20200523-matrix.html
Copyright © 2020-2023  润新知