AtCoder Beginner Contest 265 F Manhattan Cafe
考虑 dp, 表示考虑到第 维, 的方案数。转移是容易的,枚举 即可,。
复杂度 ,无法接受,考虑下标拆绝对值后前缀和优化。简单讨论一下就行。以 的情况为例:
- , 能从 转移;
- , 能从 转移;
- , 能从 转移。
也就是说我们只要维护对角线前缀和就好了。
要注意下标越界的问题。对于第 种情况,能转移的是一段前缀或后缀,只要特判下标是否越界即可;对于第 种情况,因为能转移的是一段区间,如果下标为负,就要找到第一个 开始转移。
想清楚了写起来挺快的,不存在难写的问题。注意一些细节问题即可,比如符号写反,或者没取模等等,别像我一样有一处漏了取模然后傻傻调试 20min 就行。
时间复杂度 ,可以通过。
code
// Problem: F - Manhattan Cafe // Contest: AtCoder - AtCoder Beginner Contest 265 // URL: https://atcoder.jp/contests/abc265/tasks/abc265_f // Memory Limit: 1024 MB // Time Limit: 6000 ms // // Powered by CP Editor (https://cpeditor.org) #include <bits/stdc++.h> #define pb emplace_back #define fst first #define scd second #define mems(a, x) memset((a), (x), sizeof(a)) using namespace std; typedef long long ll; typedef unsigned long long ull; typedef double db; typedef long double ldb; typedef pair<ll, ll> pii; const int maxn = 1010; const int mod = 998244353; int n, m, a[maxn], b[maxn], f[2][maxn][maxn], g[3][maxn][maxn]; void solve() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++i) { scanf("%d", &a[i]); } for (int i = 1; i <= n; ++i) { scanf("%d", &b[i]); } f[0][0][0] = 1; for (int i = 1, o = 1; i <= n; ++i, o ^= 1) { mems(f[o], 0); mems(g, 0); for (int j = 0; j <= m; ++j) { for (int k = 0; k <= m; ++k) { g[0][j][k] = f[o ^ 1][j][k]; if (j && k) { g[0][j][k] = (g[0][j][k] + g[0][j - 1][k - 1]) % mod; } } } for (int j = m; ~j; --j) { for (int k = 0; k <= m; ++k) { g[1][j][k] = f[o ^ 1][j][k]; if (j < m && k) { g[1][j][k] = (g[1][j][k] + g[1][j + 1][k - 1]) % mod; } } } for (int j = 0; j <= m; ++j) { for (int k = m; ~k; --k) { g[2][j][k] = f[o ^ 1][j][k]; if (j && k < m) { g[2][j][k] = (g[2][j][k] + g[2][j - 1][k + 1]) % mod; } } } for (int j = 0; j <= m; ++j) { for (int k = 0; k <= m; ++k) { if (a[i] <= b[i]) { if (j - 1 >= 0 && k - b[i] + a[i] - 1 >= 0) { f[o][j][k] = (f[o][j][k] + g[0][j - 1][k - b[i] + a[i] - 1]) % mod; } if (j + 1 <= m && k - b[i] + a[i] - 1 >= 0) { f[o][j][k] = (f[o][j][k] + mod - g[1][j + 1][k - b[i] + a[i] - 1]) % mod; } int x = j - b[i] + a[i], y = k; if (x < 0) { y += x; x = 0; } if (y >= 0) { f[o][j][k] = (f[o][j][k] + g[1][x][y]) % mod; } if (j + a[i] - b[i] - 1 >= 0 && k - 1 >= 0) { f[o][j][k] = (f[o][j][k] + g[0][j + a[i] - b[i] - 1][k - 1]) % mod; } } else { if (j - a[i] + b[i] - 1 >= 0 && k - 1 >= 0) { f[o][j][k] = (f[o][j][k] + g[0][j - a[i] + b[i] - 1][k - 1]) % mod; } if (j - a[i] + b[i] - 1 >= 0 && k + 1 <= m) { f[o][j][k] = (f[o][j][k] + mod - g[2][j - a[i] + b[i] - 1][k + 1]) % mod; } int x = j, y = k - a[i] + b[i]; if (y < 0) { x += y; y = 0; } if (x >= 0) { f[o][j][k] = (f[o][j][k] + g[2][x][y]) % mod; } if (j - 1 >= 0 && k + b[i] - a[i] - 1 >= 0) { f[o][j][k] = (f[o][j][k] + g[0][j - 1][k + b[i] - a[i] - 1]) % mod; } } } } } int ans = 0; for (int i = 0; i <= m; ++i) { for (int j = 0; j <= m; ++j) { ans = (ans + f[n & 1][i][j]) % mod; } } printf("%d\n", ans); } int main() { int T = 1; // scanf("%d", &T); while (T--) { solve(); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话