import sys
input = sys.stdin.readline
inf = float('inf')
MOD = 998244353
for _ in range(int(input())):
n, m, q, k = map(int, input().split())
listener = [[] for _ in range(k)]
for _ in range(q):
x, y, t = map(lambda x: int(x)-1, input().split())
if t < k:
listener[t].append((x, y))
dp = [[0]*m for _ in range(n)]
dp[0][0] = 1
total_ways = 0
shortest_time = -1
vis = [[0] * m for _ in range(n)]
for _ in range(k):
for r, c in listener[_]:
vis[r][c] = 1
nxt = [[0]*m for _ in range(n)]
for i in range(n):
prev = 0
for j in range(m):
if vis[i][j]:
prev = 0
continue
nxt[i][j] = (nxt[i][j]+prev) % MOD
prev = (prev+dp[i][j]) % MOD
for j in range(m):
prev = 0
for i in range(n):
if vis[i][j]:
prev = 0
continue
nxt[i][j] = (nxt[i][j]+prev) % MOD
prev = (prev+dp[i][j]) % MOD
dp = nxt
if dp[n - 1][m - 1] > 0 and shortest_time == -1:
shortest_time = _ + 1
total_ways = (total_ways + dp[-1][-1]) % MOD
if shortest_time == -1:
print(-1)
else:
print(f"{total_ways} {shortest_time}")
先思考一种简单情况,没有检查官的时候,合法的方案数
定义dp[当前时刻][i][j]
当前时刻的单元格会从上方所有单元格和左边所有单元格转移过来,因此
dp[当前时刻][i][j]+=dp[上一时刻][i-1][j]+dp[上一时刻][i-2][j]....+dp[上一时刻][0][j]
dp[当前时刻][i][j]+=dp[上一时刻][i][j-1]+dp[上一时刻][i][j-2]....+dp[上一时刻][i][0]
可以依靠前缀和累计计算
dp[0][0][0]=1表示初始状态方案数为1
依次计算下一时刻状态
每计算完一次,累加最下方单元格值作为总方案数
再考虑有检察官的情况
通过vis记录当前位置是否有检察官
for r, c in listener[_]:
vis[r][c] = 1
当计算到有检察官的时候,将前缀和置为0,跳过当前单元格即可
if vis[i][j]:
prev = 0
continue
最早的时刻可以通过记录右下单元格最早不为0的时刻,剩下的就是注意一些边界细节之类的

京公网安备 11010502036488号