题目
题意:给定一个
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();
}
}