2025CSP-S模拟赛17 比赛总结

2025CSP-S模拟赛17

T1 zzy 的金牌

考虑如何判断一个可重集 \(\{s_1,s_2,\dots s_n\}\) 是否可能成为答案,这个可以贪心:将 \(s\)\(a\) 分别从小到大排序后,若 \(\forall i,s_i \geq a_i\)\(\sum s - \sum a=k\) 则合法。于是乎所求即为 \(b_1,b_2,\dots b_n\) 的数量,其中 \(b\) 满足 \(b_i+a+i \geq b_{i-1}+a_{i-1}\)\(\sum b_i=k\)

考虑设计 dp:\(f_{i,j,k}\) 表示 \(b\) 的前 \(i\) 项有多少种填法满足 \(b_i=j\)\((\sum_{x\le i}b_x)=k\)。转移很简单,\(f_{i,j,k}\rightarrow f_{i+1,l,k+l}(l+a_{i+1} \geq j+a_i)\)

此时的时间复杂度来到 \(O(nk^3)\)

考虑令 \(g_{i,k-j,j}=f_{i,j,k}\),则 \(g_{i,k-j,j}\rightarrow g_{i+1,k,l}(l+a_{i+1} \geq j+a_i)\)。容易发现这是对 \(g_{i+1,k}\) 的一个后缀加,差分维护即可。

时间复杂度 \(O(nk^2)\)

#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long

using namespace std;

int read() {
	int x = 0; char ch = getchar();
	while (ch < '0' || ch > '9') ch = getchar();
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return x;
}
const int P = 131;
const int MOD = 998244353;
const int N = 300 + 10;
int n, kk, a[N];
int f[N][N][N]; 
signed main() {
	n = read(), kk = read();
	for (int i = 1; i <= n; i++) {
		a[i] = read();
	}
	sort(a + 1, a + 1 + n);
	f[0][0][0] = 1;
	for (int i = 0; i <= n; i++) {
		for (int k = 0; k <= kk; k++) {
			for (int j = 0; j <= k; j++) {
				if (!f[i][k - j][k]) continue;
				int l = max(0ll, a[i] + j - a[i + 1]), r = kk - k;
				if (l <= r) {
					(f[i + 1][k][k + l] += f[i][k - j][k]) %= MOD;
					((f[i + 1][k][k + r + 1] -= f[i][k - j][k]) += MOD) %= MOD;
				}
			}
			for (int j = 0; j <= kk; j++) {
				(f[i + 1][k][j + 1] += f[i + 1][k][j]) %= MOD;
			}
		}
	}
	int ans = 0;
	for (int j = 0; j <= kk; j++) {
		(ans += f[n][j][kk]) %= MOD;
	}
	printf("%lld\n", ans);
	
	return 0;
}

T2 口粮输送

T3 作弊

T4 合作的力量

posted @ 2025-07-15 21:13  Zctf1088  阅读(13)  评论(0)    收藏  举报