专栏文章
AT_arc156_b 题解
AT_arc156_b题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @miqkutxc
- 此快照首次捕获于
- 2025/12/04 06:27 3 个月前
- 此快照最后确认于
- 2025/12/04 06:27 3 个月前
这道题其实不难。
我们先把原先 集合去重。
然后,我们观察最终集合 的情况。
先定义 表示后来加入的数中最大的值, 表示最终集合 中的数字 的数量。
我们发现,最终集合需要满足对于任意的整数 ,。因为如果存在整数 ,,那么无论如何,加入集合 的数都不可能超过 ,要超过 需要先把 填好。
因此,我们可以枚举 的值。
对于当前的 ,我们统计出原先 集合中小于等于 的数字个数,然后再加上 ,即为最终 集合 的值。
我们可以发现,只要满足 3 段前说明的条件,那么最终的 一定是合法的,我们已经对 集合去重了,那么每一个 可以取到的最小值就是 。我们使用插板法计算可能的结果数。
设 ,那么一共有 个空,需要插 个板子。对于当前 ,答案就是 。
需要注意的是,如果对于某个 ,原集合 中存在 ,那么 , 的贡献已经在 中统计过了。所以不需要统计这个 。
代码:
CPP#include<bits/stdc++.h>
#define int long long // 开 long long 是为了防止取模前爆 int
using namespace std;
const int N = 400005, P = 998244353; // 数据范围及模数
int n, k; // 原集合 A 的元素数量及操作个数
bool f[N]; // 标记某数是否存在于原集合
int sum = 0; // 当前枚举到的 m 对应的 W 值
int ans = 0; // 答案
int frac[N]; // 阶乘数组
int ksm(int a, int n) { // 快速幂
if(n == 0) return 1;
if(n == 1) return a % P;
int d = ksm(a, n / 2);
d = d * d % P;
if(n & 1) d = d * a % P;
return d;
}
int inv(int a) { // 逆元
return ksm(a, P - 2); // 不会的可以去看 OI wiki 乘法逆元
}
int C(int n, int m) { // 组合数
return frac[n] * inv(frac[n - m]) % P * inv(frac[m]) % P; // 计算组合数
}
signed main() {
cin >> n >> k;
frac[0] = 1;
for(int i = 1; i <= n + k; i ++) frac[i] = frac[i - 1] * i % P;
for(int i = 1; i <= n; i ++) {
int a;
cin >> a;
f[a] = 1; // 标记 a 存在于原集合 A
}
sum = k;
for(int i = 0; ; i ++) {
if(f[i]) sum ++; // 修改当前的 M 值
if(sum < i) break; // 无法满足条件
if(f[i + 1]) continue; // 无需统计
ans += C(sum - 1, i); // 将贡献加入答案
ans %= P; // 对 P 取模
}
printf("%d\n", ans); // 输出答案
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...