codeforces 1188 C. Array Beauty (dp)

题目链接:https://codeforces.com/contest/1188/problem/C?mobile=true

美丽值的最大值就是将最大的数平分到 \((k-1)\) 个空位里,即 \(\frac{x}{k-1}\),美丽值恰好为 \(v\) 的方案数不好算,考虑计算美丽值大于等于 \(v\) 的方案数

\(dp[i][j]\) 表示前 \(i\) 个数选了 \(j\) 个数的方案数,其中 \(i\) 必选,维护前缀和 \(O(1)\) 转移

时间复杂度为 \(O(nk \times \frac{x}{k-1}) = O(nx)\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 1010;
const int M = 998244353;

int n, k;
int a[maxn], dp[maxn][maxn], sum[maxn][maxn], f[100010];

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	n = read(), k = read();
	int x = 0;
	for(int i = 1 ; i <= n ; ++i) a[i] = read(), x = max(x, a[i]); 
	a[0] = -1000000007;
	sort(a + 1, a + 1 + n);
	
	for(int v = 1 ; v * (k-1) <= x ; ++v){
		int pos = 0;
		dp[0][0] = 1;
		sum[0][0] = 1;
		for(int i = 1 ; i <= n ; ++i){
			while(a[i] - a[pos+1] >= v && pos+1 <= i-1) {
				++pos;
			}
			for(int j = 0 ; j <= k ; ++j){
				if(j) dp[i][j] = sum[pos][j-1];
				sum[i][j] = (sum[i-1][j] + dp[i][j]) % M;
			}
			f[v] = (f[v] + dp[i][k]) % M;
		}
	}
	
	for(int v = 1 ; v <= x / (k-1) ; ++v){
		f[v] = ((f[v] - f[v+1]) % M + M) % M;
	}
	
	int ans = 0;
	for(int v = 1 ; v <= x / (k-1) ; ++v){
		ans = (ans + 1ll * v * f[v] % M) % M;
	}
	
	printf("%d\n", ans);
	
	return 0;
}
posted @ 2021-08-23 21:27  Tartarus_li  阅读(31)  评论(0编辑  收藏  举报