题意: 给定
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
1≤n≤5000,ai,d≤109
题解: 考虑
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[i−1][j][0]+f[i−1][j][1]×(a[i−1]+d≤a[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[i−1][j−1][0]+f[i−1][j−1][1](j≥1)
其中选择 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;
}