专栏文章
题解:CF2125E Sets of Complementary Sums
CF2125E题解参与者 2已保存评论 4
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 4 条
- 当前快照
- 1 份
- 快照标识符
- @mioqh9lq
- 此快照首次捕获于
- 2025/12/02 23:29 3 个月前
- 此快照最后确认于
- 2025/12/02 23:29 3 个月前
如果将 中的数从小到大排序,临位作差得到查分数组,那么不难发现对 进行如下操作, 的差分数组是不变的:
- 将 的所有值都增加或减少同一个数;
- 在 最后添加一个已经出现过的数。
因为这两种操作的本质都是将 整体增加或减少同一个数。不妨将从 开始进行多次这样操作后得到的新数组 都归为一个等价类。换言之,一个等价类的 所对应的 的查分数组是相同的。(话说等价类是这个意思吗 QwQ)
如果要用某个 代表这个等价类,这个 一定会满足:
- 最小值为 ;
- 没有重复元素。
如果最小值不为 ,我们可以将 整体减 。如果有重复元素,可以视作从没有重复元素的 不断扩展而来。
用这样的 代表整个等价类的另一个好处是,可以方便刻画「 大小为 」和「 中最大值不超过 」这两个条件。即:
- ;
- ,即 。
另一个问题是,一个等价类中的 所对应的 的差分数组是相同的,不代表 是相同的。
这样考虑,从那个基本的 (有 且无重复元素)开始,每次在最后添加一个 ,就能使 的最大值增大 。初始 中最大值为 ,最终 的最大值为 。所以一个等价类中的 所对应的 的数量为 。
也就是说,对于最终答案的计算,我们并不需要得知 的具体值,而是只需要确定 。于是考虑将「和」放进 DP 状态中并统计方案数。
另外这个「 中有 」不太好刻画。一个比较偷懒的解决方式是,我们将 整体减一并把 去掉,这个 就是刚才的 。然后 的长度变为 ,总和减少了 。这些都是定值是极其方便的。
然后 DP。设 表示满足以下条件的 的数量:
- ;
- ;
- 。
注意到,初始令 ,进行若干次下面任一操作后,一定可以得到满足「」的 :
- 将 全部加一;
- 将 全部加一,接着在 开头添加一个 。
相对应的可以得到转移方程:
同时注意到 ,且 ,所以 DP 第一维是根号级别的。这样复杂度就对了。
最后因为神秘原因需要特判一下 。
CPP#include <bits/stdc++.h>
using namespace std;
const int P = 998244353, N = 2e5 + 10, M = 800;
int f[M][N];
int n, x;
int dp(int n, int s) {
if (n >= M || s < 0) return 0;
return f[n][s];
}
int solve() {
cin >> n >> x;
if (n == 1) return x;
int res = 0;
for (int s = 1; s <= x + 1; ++ s ) {
res = (res + 1ll * dp(n - 1, s - n) * (x - s + 2)) % P;
}
return res;
}
signed main() {
f[0][0] = 1;
for (int i = 1; i < M; ++ i )
for (int j = i * (i + 1) / 2; j < N; ++ j ) {
f[i][j] = (f[i][j - i] + f[i - 1][j - i]) % P;
}
int T;
cin >> T;
while (T -- ) cout << solve() << '\n';
return 0;
}
相关推荐
评论
共 4 条评论,欢迎与作者交流。
正在加载评论...