Atcoder ABC311F Yet Another Grid Task

发布时间 2023-07-24 08:04:27作者: lhzawa

发现 \((i, j)\) 若为黑色则就会有一个 \((i, j)\) 为最高点的阶梯形的图形被染黑(阶梯形指对于 \(1\le i\le x\)\(i\) 列第 \(x - i + 1\) 行及以下都是黑色)。

那么能发现其实每个列只需要记录最高的黑色点行数即可,因为及其以下的点肯定都是黑色。
考虑设 \(f_{i, j}\) 为第 \(i\) 列最高的黑色点的行数为 \(j\)
容易发现无法转移到 \((i, j)\) 的容就是 \((i - 1, j + 2\sim n)\),因为根据阶梯形这一列的最高黑色点还会高一些(行数应为 \(j - 1\sim n - 1\)),其他的则都可以转移过来,于是就有 \(f_{i, j} = \sum\limits_{k = 0}^{\min(j + 1, n)} f_{i - 1, k}(j \ge mx_i)\)\(mx_i\) 为初始给定的矩阵第 \(i\) 列最高的黑色点的行数。
然后用前缀和优化 \(f\) 转移即可。

时间复杂度 \(O(nm)\)

// lhzawa(https://www.cnblogs.com/lhzawa/)
// Problem: F - Yet Another Grid Task
// Contest: AtCoder - Toyota Programming Contest 2023#4(AtCoder Beginner Contest 311)
// URL: https://atcoder.jp/contests/abc311/tasks/abc311_f
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
const int N = 2e3 + 10;
int g[N][N];
int mx[N];
char s[N];
const int mod = 998244353;
int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%s", s + 1);
		for (int j = 1; j <= m; j++) {
			if (s[j] == '#') {
				mx[j] = max(mx[j], n - i + 1);
			}	
		}
	}
	for (int i = 0; i <= n; i++) {
		g[0][i] = 1;
	}
	for (int i = 1; i <= m; i++) {
		for (int j = mx[i]; j <= n; j++) {
			g[i][j] = ((j == 0 ? 0 : g[i][j - 1]) + g[i - 1][min(j + 1, n)]) % mod;
		}
	}
	printf("%d\n", g[m][n]);
	return 0;
}