专栏文章
题解:CF1188C Array Beauty
CF1188C题解参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @miqzb6k3
- 此快照首次捕获于
- 2025/12/04 13:12 3 个月前
- 此快照最后确认于
- 2025/12/04 13:12 3 个月前
Array Beauty
这道题目有两个关键的 trick:
-
- 我们对数组进行了排序。为什么是对的?我们来思考一下,最后我们在选出 个数字以后我们计算贡献又会强行使得数组有序,原因很简单,因为 如果 ,那么绝对值就会使得 和 交换位置,而因为取 ,所以值域相近的两个数字会在一起。所以这道题目不管如何,最后答案在计算时数组一定是有序的。这也说明了排序是正确的,并且对于解题有着一定帮助。
-
- 我们直觉告诉我们,我们需要枚举每种可能的答案,因为答案值域很小,或者说根据结论,要使最小间隙最大,就必须要均匀分配间隙,也就是说对于数列 ,我们应当选择出类似 ,这样才能做到最大,而不是 ,看着最大的大,但是最小的也更小了。于是枚举答案可行。
-
- 在枚举每种答案时,我们定义出了一个状态 ,强制选择第 个数字,并且已经选了 个数字,有没有到达 答案时的方案数,由于状态是两维的,转移枚举 又是 的,考虑前缀和优化明显要考虑很多东西,例如容斥,等等。于是我们考虑 状态前缀化,然后转化为差分数组求出答案。则状态设为 表示前 个数字,且强制选 ,已经选了 个数字,且满足间隙大于等于枚举答案的方案数。
转移直接双指针 + 前缀和即可,我称之为 双前组合。
The code
CPP#include<bits/stdc++.h>
#define L(i, a, b) for(int i = (a); i <= (b); i++)
#define R(i, a, b) for(int i = (a); i >= (b); i--)
#define ll long long
using namespace std;
const int N = 1005 + 10;
const int mod = 998244353;
ll a[N], n, k, ans[1000001], F[1005][N], sum[N][N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> k;
L(i, 1, n) cin >> a[i];
sort(a+1, a+n+1);
R(i, (a[n]-a[1])/(k-1), 0) {
F[0][0] = sum[0][0] = 1;
int p = 0;
L(j, 1, n) {
while(p < j && a[j] - a[p+1] >= i) p++;
L(x, 0, k) {
if(x) F[j][x] = sum[p][x-1];
sum[j][x] = (sum[j-1][x] + F[j][x]) % mod;
}
ans[i] = (ans[i] + F[j][k]) % mod;
}
// cout << ans[i] << '\n';
}
ll Ans = 0;
R(i, (a[n]-a[1])/(k-1), 0)
Ans = (Ans + 1LL * (ans[i] - ans[i+1] + mod) % mod * i % mod) % mod;
cout << Ans << '\n';
return 0;
}
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...