Cross Coloring(思维/map/逆向)

题目
题意:给定一个 n ∗ m n*m n∗m的矩阵,初始无色,有k种颜色,q个操作。每次操作选择位置 x i , y i ( 1 < = x i < = n , 1 < = y i < = m ) x_i,y_i(1<=x_i<=n,1<=y_i<=m) xi​,yi​(1<=xi​<=n,1<=yi​<=m),选择任意一种颜色 c , 1 < = c < = k c,1<=c<=k c,1<=c<=k,将第 x i x_i xi​行,第 y i y_i yi​列的元素都染上颜色c。通过这q个操作后,问最终得到的 n ∗ m n*m n∗m最终有多少种染色情况。

思路:对于染不到颜色的位置 ( x , y ) (x,y) (x,y),我们可以忽略,因为这些位置到最后也是无色。对于染得到颜色的位置 ( x , y ) (x,y) (x,y),我们重点关注能染到它的最后一次操作(因为之前的操作染上的颜色,都会被覆盖掉)。我们可以发现,如果当前的操作,能唯一决定至少一个位置的颜色,那么这次操作就是有效的,且它的选择有k种;否则就是无效的操作。

怎么判断一次染色操作 ( x i , y i ) (x_i,y_i) (xi​,yi​)是否至少一个位置的颜色,我们就看后边的操作中,是否满足以下任意一种情况:
1、是否把所有行都染上了
2、是否把所有列都染上了
3、把第 x i x_i xi​行染上了,且把第 y i y_i yi​列染上了
我们可以逆序遍历操作,维护行和列的染色即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 200010;
const int mod = 998244353;

bool col[maxn], row[maxn];
int numr, numc;
int n, m, k, q;
int x[maxn], y[maxn];
void solve() {
	scanf("%d%d%d%d", &n, &m, &k, &q);
	for (int i = 0; i < q; ++i) {
		scanf("%d%d", &x[i], &y[i]);
	}
	memset(row, 0, sizeof(row));
	memset(col, 0, sizeof(col));
	numr = numc = 0;
	int ans = 1;
	for (int i = q - 1; i >= 0; --i) {
		if (numr == n || numc == m || (row[x[i]] && col[y[i]])) {
			continue;
		}
		if (!row[x[i]]) {
			row[x[i]] = true;
			++numr;
		}
		if (!col[y[i]]) {
			col[y[i]] = true;
			++numc;
		}
		ans = 1LL * ans * k % mod;
	}
	printf("%d\n", ans);
}
int main() {
	int t;
	scanf("%d", &t);
//	t = 1;
	while (t--) {
		solve();
	}
}
上一篇:SpringMVC:RESTFUL


下一篇:每日刷题计划Day[26]