专栏文章

题解:P14537 [OII 2025] 双色金字塔 / Piramide bicolore

P14537题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@min5zrtf
此快照首次捕获于
2025/12/01 21:08
3 个月前
此快照最后确认于
2025/12/01 21:08
3 个月前
查看原文

题解

模拟赛的时候竟然场切了,赛后一看是紫。
看到这题的第一眼完全没思路,先强行模拟打点暴力分。之后的看看样例手玩一下吧。
首先考虑到向上能是黑色比白色要严格,所以我们考虑如何判断是否是黑色。我们将自己造的数据所有答案为 11 的询问向下在第 00 层对应的矩阵全部打出来,惊奇的发现映入眼帘的是一条全 00 或者全 11 的对角线,随后两边分别跟随了两条颜色与之不同的斜线。于是我们大胆猜测这必然是答案为 11 的充要条件。
具体证明我这里使用递推法,虽然不严谨但主要还是让大家感性理解,并且我的构造过程只包括左上到右下的对角线,另一边同理,11 表示黑,00 表示白,22 表示未处理,33 表示黑白均可。
  • 00 步:
11
  • 11 步:由于对角线限制,方案唯一。
1010
0101
  • 22 步:先把上一次操作所有为 11 的处理。
102102
010010
201201
简单推理得到剩下的只能填白色。
100100
010010
001001
  • 33 步:依旧先上一次操作所有为 11 的处理。
10221022
01020102
20102010
22012201
再把附近的两行 00 处理。
10021002
01000100
00100010
20012001
最后我们发现剩下未处理的地方由于剩下了三个白色,所以无论填什么向上都只会保留白色,所以我们不需要处理最外面的 00
10031003
01000100
00100010
30013001
不难发现,这个优秀的性质能一直维持直到映射到了第 00 层。但是在第 00 层的时候由于题目中相邻立方体不同色的要求,把所有的已经确定的颜色反转不影响结果。
最终,我们得证在题目定义下第 hh 层第 ii 行第 jj 列颜色为黑色当且仅当其对应第 00 层的矩阵内部存在一条全黑或者全白的对角线,对角线向上两条斜线与向下的两条斜线颜色全部与对角线颜色不相同,当 h=1h = 1 时特判即可(结合代码感性理解吧)。
实现时维护两个斜向方向上的对角线的前缀和即可快速判断,时间复杂度 O(N2+Q)O(N^2+Q)
CPP
#include <bits/stdc++.h>
#define maxn 5010
using namespace std;
bool f[maxn][maxn];
int pre1[maxn][maxn];
int pre2[maxn][maxn];
int n, q;
void init(int N, vector<string> M)
{
	n = N;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			f[i][j] = M[i][j] - '0';
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			pre1[i][j] = (j ? pre1[i][j - 1] : 0) + f[(i + j) % n][j], pre2[i][j] = (j ? pre2[i][j - 1] : 0) + f[(i - j + n) % n][j];
}
inline int get1(const int& x, const int& y, const int& h)
{
	int ln = (x - y + n) % n;
	return pre1[ln][y + h] - (y ? pre1[ln][y - 1] : 0);
}
inline int get2(const int& x, const int& y, const int& h)
{
	int ln = (x + y + h) % n;
	return pre2[ln][y + h] - (y ? pre2[ln][y - 1] : 0);
}
bool query(int h, int x, int y)
{
	if (h == 0) return f[x][y];
	if (h == 1) return (f[x][y] && f[x + 1][y + 1] && !f[x + 1][y] && !f[x][y + 1]) || (!f[x][y] && !f[x + 1][y + 1] && f[x + 1][y] && f[x][y + 1]);
	int sum1 = get1(x, y, h), sum2 = get1(x + 1, y, h - 1), sum3 = get1(x, y + 1, h - 1), sum4 = get1(x + 2, y, h - 2), sum5 = get1(x, y + 2, h - 2);
	if (!sum1 && sum2 == h && sum3 == h && sum4 == h - 1 && sum5 == h - 1) return 1;
	if (sum1 == h + 1 && !sum2 && !sum3 && !sum4 && !sum5) return 1;
	sum1 = get2(x, y, h), sum2 = get2(x, y, h - 1), sum3 = get2(x + 1, y + 1, h - 1), sum4 = get2(x, y, h - 2), sum5 = get2(x + 2, y + 2, h - 2);
	if (!sum1 && sum2 == h && sum3 == h && sum4 == h - 1 && sum5 == h - 1) return 1;
	if (sum1 == h + 1 && !sum2 && !sum3 && !sum4 && !sum5) return 1;
	return 0;
}
#ifndef ONLINE_JUDGE
int main()
{
	cin >> n >> q;
	vector<string> s(n);
	for (int i = 0; i < n; i++) cin >> s[i];
	init(n, s);
	static int h, x, y;
	while (q--) cin >> h >> x >> y, cout << query(h, x, y) << '\n';
}
#endif

评论

0 条评论,欢迎与作者交流。

正在加载评论...