牛客练习赛69 D

题意: 给定 n n n个数,从中选择 k k k个数 ( k ∈ [ 1 , n ] ) (k\in[1,n]) (k[1,n])个数加上 d d d,问选择 k k k个数的概率,概率对 998244353 998244353 998244353取模, n n n个数的排序自行选择,使得概率越大越好。
数据范围: 1 ≤ n ≤ 5000 , a i , d ≤ 1 0 9 1\leq n\leq 5000, a_i,d\leq 10^9 1n5000,ai,d109

题解: 考虑 d p dp dp,使得概率越大那么就是按照升序排序
f [ i ] [ j ] [ 0 ] f[i][j][0] f[i][j][0]表示从前 i i i个数中选 j j j个数加 d d d,且第 i i i个数不加 d d d
f [ i ] [ j ] [ 1 ] f[i][j][1] f[i][j][1]表示从前 i i i个数中选 j j j个数加 d d d,且第 i i i个数加了 d d d

状态转移:
f [ i ] [ j ] [ 0 ] = f [ i − 1 ] [ j ] [ 0 ] + f [ i − 1 ] [ j ] [ 1 ] × ( a [ i − 1 ] + d ≤ a [ i ] ) f[i][j][0] = f[i-1][j][0]+f[i-1][j][1]\times(a[i-1]+d\leq a[i]) f[i][j][0]=f[i1][j][0]+f[i1][j][1]×(a[i1]+da[i])
f [ i ] [ j ] [ 1 ] = f [ i − 1 ] [ j − 1 ] [ 0 ] + f [ i − 1 ] [ j − 1 ] [ 1 ] ( j ≥ 1 ) f[i][j][1]=f[i-1][j-1][0]+f[i-1][j-1][1](j\geq1) f[i][j][1]=f[i1][j1][0]+f[i1][j1][1](j1)

其中选择 k k k个数的总情况为 C n k C_n^k Cnk

代码:

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

typedef long long ll;
const int mod = 998244353;
const int N = 5010;
int q[N], n, d;
int f[N][N][2];
//f[i][j][0]表示从前i个数中选择j个数+d,同时第i个数没选择 
//f[i][j][0]表示从前i个数中选择j个数+d,同时第i个数选择了 

int fac[N], inv;
int qp(int a, int b) {
	int ans = 1;
	while(b) {
		if(b & 1) ans = 1ll * ans * a % mod;
		a = 1ll * a * a % mod;
		b >>= 1; 
	} 
	return ans; 
}

int main()
{
	scanf("%d%d", &n, &d);
	for(int i = 1; i <= n; i++) scanf("%d", &q[i]);
	fac[0] = 1;
	for(int i = 1; i <= n; i++) fac[i] = 1ll * fac[i - 1] * i % mod;
	inv = qp(fac[n], mod - 2);

	sort(q + 1, q + 1 + n);
	f[0][0][0] = 1;
	for(int i = 1; i <= n; i++)
		for(int j = 0; j <= i; j++) {
			if(j) f[i][j][1] += f[i - 1][j - 1][1] + f[i - 1][j - 1][0];
			if(q[i - 1] + d <= q[i]) f[i][j][0] += f[i - 1][j][1];
			f[i][j][0] += f[i - 1][j][0];
			f[i][j][0] %= mod, f[i][j][1] %= mod;
		}
	
	for(int i = 1; i <= n; i++) printf("%d\n", 1ll * (f[n][i][0] + f[n][i][1]) * inv % mod * fac[i] % mod * fac[n - i] % mod);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值