Serval and Bonus Problem
题目大意
长度为 l 的线段,有 n 个区间端点随机分布,然后问你期望有多少长度被至少 k 个区间覆盖。
思路
首先这种随机分布的期望题考虑也把随机的时间弄成一个平均分布。 在这里就是我们可以理解为这
2
n
2n
2n 个端点是均匀分布在
l
l
l 上的,那每段长度就是
l
2
n
+
1
\dfrac{l}{2n+1}
2n+1l?。
然后我们就可以考虑 DP,设
f
i
,
j
f_{i,j}
fi,j? 为
i
i
i 个端点,当前有
j
j
j 个左端点没有匹配。 那没有匹配说明要延伸过去,那只要延伸过去的数量大于等于
k
k
k,就说明这个段是贡献的。
然后我们考虑每个位置放左端点还是右端点,注意如果是右端点你会选跟哪个左端点,所以要乘上
j
j
j。
然后你考虑怎么计算答案,你前面保证了这个左端点,那右端点你也应该要保证吧。 那左右端点其实是一样的,所以你可以直接用 DP 的值,就是两个乘起来,然后左右端点匹配是一个阶乘。
然后你前面算的是方案你要除总方案才是概率,然后总方案是
f
2
n
,
0
f_{2n,0}
f2n,0?。
然后就可以啦。
代码
#include<cstdio>
#define ll long long
#define mo 998244353
using namespace std;
const int N = 2005;
int n, k, l;
ll f[N << 1][N], jc[N];
ll ksm(ll x, ll y) {
ll re = 1;
while (y) {
if (y & 1) re = re * x % mo;
x = x * x % mo; y >>= 1;
}
return re;
}
ll clac(int n, int k) {
f[0][0] = 1; ll ans = 0;
for (int i = 0; i < 2 * n; i++) {
for (int j = 0; j <= i && j <= n; j++) {
(f[i + 1][j + 1] += f[i][j]) %= mo;
if (j) (f[i + 1][j - 1] += f[i][j] * j % mo) %= mo;
}
}
for (int i = 1; i <= 2 * n; i++)
for (int j = k; j <= n; j++)
(ans += f[i][j] * f[2 * n - i][j] % mo * jc[j]) %= mo;
return ans * ksm(f[2 * n][0], mo - 2) % mo;
}
int main() {
scanf("%d %d %d", &n, &k, &l); l = l * ksm(2 * n + 1, mo - 2) % mo;
jc[0] = 1; for (int i = 1; i <= n; i++) jc[i] = jc[i - 1] * i % mo;
printf("%lld", clac(n, k) * l % mo);
return 0;
}
|