CF 1188C Array Beauty(DP)
文章目录
题目描述
给出一个序列 $a[1…n]$ 和 $k$
求 $a$ 所有长度为 $k$ 的子序列的价值和
定义一个序列 $b[1…k]$ 的价值为 $min(abs(b_i-b_j))$,即最接近的两个数的差
$1 \le k,n \le 10^4$
简要做法
由抽屉原理,最大价值 $\le \frac{max(a_i)}{k-1}$
考虑枚举价值 $v$,统计价值等于 $v$ 的方案数
发现等于很难统计,不妨统计大于等于的方案数
$f(i,j)$ 表示前 $i$ 个数中选 $j$ 个数,$i$ 必选的方案数
$f(i,j)=f(i-1,j) + f(pos,j-1)$
$pos$ 为最后一个满足 $a_i - a_pos \geq v$ 的位置
这东西是有单调性的,双指针维护 $pos$ 即可
参考代码
#include <stdio.h>
#include <algorithm>
#include <memory.h>
int read(int x = 0, int f = 0, char ch = getchar())
{
while ('0' > ch or ch > '9')
f = ch == '-', ch = getchar();
while ('0' <= ch and ch <= '9')
x = x * 10 + (ch ^ 48), ch = getchar();
return f ? -x : x;
}
#define int long long
const int N = 1e4 + 5;
const int P = 998244353;
int n, k, ans;
int a[N], f[N][N];
signed main()
{
n = read(), k = read(), f[0][0] = 1;
for (int i = 1; i <= n; i++)
a[i] = read();
std::sort(a + 1, a + 1 + n);
for (int v = 1; v <= a[n] / (k - 1); (ans += f[n][k]) %= P, v++)
for (int i = 1, pos = 0; i <= n; i++)
{
f[i][0] = 1;
while (a[i] - a[pos + 1] >= v)
pos++;
for (int j = 1; j <= k; j++)
f[i][j] = (f[i - 1][j] + f[pos][j - 1]) % P;
}
return printf("%lld", ans), 0;
}