ARC162F Montage
脑子被吃掉了。
手玩一下,容易转化题意为:
按行从上到下填 矩阵,设第 个非空行上是 的位置的集合为 ,满足:
- 对于任意 ,令 。
- 若 ,则 中所有元素均比 中任意元素小,即 。
- 若 ,则 从小到大排序后, 为 的后缀,为 的前缀,即 。
现在这个限制是从右上角走到左下角,那不如先把行翻转一下,就变成了从左上角到右下角:
- ,。
- ,。
那我们直接把空行删掉,令 表示考虑到第 行,第 行一共有 个 ,最右边的 的位置为 的方案数。转移枚举新的最右边的 的位置 , 的大小 , 的大小 ,转移系数就是个组合数:
枚举非空的行数,答案就是:
直接做是 的。利用不同的 转移相同可用前缀和优化至 。
然后我们发现把矩阵转置一下,将 交换不影响答案,也就是说我们可以把空的列也拿出来。于是每个 就是一段区间了,且 要么相交不包含要么相邻, 在 的右边。
将 重新定义为 ,满足以上限制的方案数。其实就是把前面的 两维交换了一下。
那么答案变为:
转移还是枚举 的两个端点 ,满足 :
然而这还是 的。由于对于不同的 贡献相同,设 为第三维差分后的 数组,可用前缀和优化至 :
单独将 的转移拎出来,这部分 :
剩下的是 的转移:
这还是 的,但是我们观察到第二维和第三维的差为定值且与 无关,所以令 :
注意到 ,再对 的第二维进行差分记作 ,前缀和优化即可做到 :
最终时间复杂度 ,空间复杂度 :
#include <bits/stdc++.h>
#define eb emplace_back
#define pb pop_back
#define mt make_tuple
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int, int> pi;
typedef tuple<int, int, int> tu;
bool Mbe;
const int N = 405;
const int P = 998244353;
int n, m, ans, f[2][N][N], g[2][N][N], C[N][N];
int qpow(int p, int q) {
int res = 1;
for (; q; q >>= 1, p = 1ll * p * p % P)
if (q & 1) res = 1ll * res * p % P;
return res;
}
void init(int lim) {
C[0][0] = 1;
for (int i = 1; i <= lim; i++) {
C[i][0] = 1;
for (int j = 1; j <= lim; j++)
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % P;
}
}
void solve() {
cin >> n >> m, init(400);
for (int i = 1; i <= m; i++)
f[1][i][i] = 1;
for (int i = 1, t = 1; i <= n; i++, t ^= 1) {
memset(f[t ^ 1], 0, sizeof(f[t ^ 1]));
memset(g[t ^ 1], 0, sizeof(g[t ^ 1]));
for (int j = 1; j <= m; j++) {
for (int k = 1; k <= j; k++)
(g[t][j][k] += g[t][j - 1][k]) %= P;
for (int k = 1; k <= j; k++)
(f[t][j][k] += g[t][j][j - k + 1]) %= P;
for (int k = 1; k <= j; k++)
(f[t][j][k] += f[t][j][k - 1]) %= P;
for (int k = 1; k <= j; k++) {
(f[t ^ 1][j][1] += f[t][j][k]) %= P;
(f[t ^ 1][j][k + 1] += P - f[t][j][k]) %= P;
(g[t ^ 1][j + 1][j + 1] += f[t][j][k]) %= P;
(g[t ^ 1][j + 1][j - k] += P - f[t][j][k]) %= P;
}
int res = 0;
for (int k = 1; k <= j; k++)
(res += f[t][j][k]) %= P;
(ans += 1ll * C[n][i] * C[m][j] % P * res % P) %= P;
}
}
cout << (ans + 1) % P << '\n';
}
bool Med;
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cerr << (&Mbe - &Med) / 1048576.0 << " MB\n";
#ifdef FILE
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
int T = 1;
// cin >> T;
while (T--) solve();
cerr << (int)(1e3 * clock() / CLOCKS_PER_SEC) << " ms\n";
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话