小红的双排列期望(hard)
小红的双排列期望(hard)
题目描述
本题为问题的困难版本,两题的唯一区别在于操作失败的代价。
小红拿到了一个长度为 $2 \times n$ 的数组 $\{a_1,a_2,\dots,a_{2\times n}\}$,初始所有元素都是 $0$,她可以进行任意次以下操作:
$\hspace{23pt}\bullet\,$尝试使 $a_i$ 加 $1$。该操作有 $b_i \%$ 的概率成功。若成功,则 $a_i$ 加 $1$;若失败,如果 $a_i$ 大于 $0$ 则会减 $1$(等于 $0$ 则无变化)。
小红希望最终 $a$ 变成一个双排列。她希望最小化操作次数,请你求出小红最优策略下,最终操作次数的期望。答案对 $10^9+7$ 取模。
【名词解释】
双排列:长度为 $2\times n$ 的双排列为两个长度为 $n$ 的排列打乱顺序后得到的数组。
排列:长度为 $n$ 的排列是由 $1,2,\dots,n$ 这 $n$ 个整数、按任意顺序组成的数组(每个整数均恰好出现一次)。例如,$\{2,3,1,5,4\}$ 是一个长度为 $5$ 的排列,而 $\{1,2,2\}$ 和 $\{1,3,4\}$ 都不是排列,因为前者存在重复元素,后者包含了超出范围的数。
【提示】
本题中,如果您需要使用到除法的取模,即计算 $\left(p\times q^{-1} \bmod M\right)$ 时,$q^{-1}$ 需要使用公式 $\left(q^{M-2} \bmod M \right)$ 得到。例如,计算 $\tfrac{5}{4} \bmod M$:
$$
\begin{array}{rll}4^{-1} &=& \left(4^{M-2} \bmod M\right) \\ &=& 250\,000\,002 \\ \hline \left(\tfrac{5}{4} \bmod M\right) &=& 5 \times4^{-1} \bmod M \\ &=& 5 \times 250\,000\,002 \bmod M \\ &=& 250\,000\,003\end{array}
$$
输入描述:
第一行输入一个正整数 $n\left(1\leqq n \leqq 10^5\right)$ 。
第二行输入 $2\times n$ 个整数 $b_i\left(1\leqq b_i \leqq 100\right)$,代表每个元素操作成功的概率百分比。
输出描述:
在一行上输出一个整数,代表最终期望对 $10^9+7$ 取模的答案。
示例1
输入
1
50 50
输出
4
说明
在这个样例中,最终期望操作次数为 $4$ 次。
解题思路
惯例开头:经典一遇到期望题就不会做.jpg
由于将每个 $a_i$ 变成某个数是相互独立的,意味着在确定数字的分配方案后,只需独立求解每个 $a_i$ 要变成的数的期望即可。因此第一个问题是每个 $a_i$ 应该变成哪个数,才能使数组 $a$ 变成双排列的期望最小。
容易贪心地知道,如果 $a_i$ 对应的 $b_i$ 越大,那么 $a_i$ 要变成的数也应该越大。这是因为都需要先分别以 $b_i$ 和 $b_j$ 对应的概率从 $0$ 变成 $\min\{a_i,a_j\}$,然后再以某个 $b_i$ 或 $b_j$ 对应的概率从 $\min\{a_i,a_j\}$ 变成 $\max\{a_i,a_j\}$。而由于由于 $b_i$ 越大,对应加 $1$ 成功的概率越大,因此当变成同一个数时,以较大 $b_i$ 对应的概率去变成该数的期望就会越小。
所以不失一般性假设 $b_1 < \cdots < b_{2n}$,那么对应的 $a_1, \ldots, a_{2n}$ 就需要依次变成 $1,1,2,2,\ldots,2n,2n$,即 $a_i = \left\lceil \frac{i+1}{2} \right\rceil \, (1 \leq i \leq 2n)$。
因此第二个问题是,对于某个给定的 $b_i$,假设对应的概率为 $p_i = \frac{b_i}{100}$,以 $p_i$ 的概率从 $0$ 变成 $\left\lceil \frac{i+1}{2} \right\rceil$ 的期望怎么求。对于一般的期望 dp 我们都会直接定义 $E(i)$ 表示从 $0$ 变到 $i$ 的期望,但会发现状态转移很难写(至少博主写不出来),所以只能参考题解的做法了。
重新定义 $E(i)$ 表示从 $i-1$ 变到 $i$ 的期望,状态转移方程为 $E(i) = p_i \cdot 1 + (1 - p_i) \cdot (1 + E(i-1) + E(i)$。其中 $p_i \cdot 1$ 这部分的意思是,有 $p_i$ 的概率操作一次从 $i-1$ 变成 $i$;否则就是失败的概率 $1-p_i$,首先消耗了一次操作所以有个 $1$,并导致 $i-1$ 变成 $i-2$,为了变成 $i$ 我们需要依次从 $i-2$ 变成 $i-1$,再变成 $i$,对应的操作次数期望就是 $E(i-1)+E(i)$。
$$
\begin{align*}
&E(i) = p_i \cdot 1 + (1 - p_i) \cdot (1 + E(i-1) + E(i)) \\
\Rightarrow& p_i \cdot E(i) = 1 + (1-p_i) \cdot E(i-1) \\
\Rightarrow& E(i) = \frac{1}{p_i} + \left(\frac{1}{p_i} - 1\right) \cdot E(i-1) \\
\Rightarrow& E(i) = \frac{100 + (100 - b_i) \cdot E(i-1)}{b_i}
\end{align*}
$$
如果对每个 $b_i$ 直接求期望会被卡到 $O(n^2)$,由于 $b_i$ 为整数且不超过 $100$,因此我们可以先暴力枚举 $b_i = 1, \ldots, 100$ 预处理出 $E(1), \ldots, E(n)$ 的结果。最后从 $0$ 变成 $i$ 的期望就是 $\sum\limits_{j=1}^{i}{E(j)}$。
AC 代码如下,时间复杂度为 $O\left(n \max\{b_i\}\right)$:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 5, M = 105, mod = 1e9 + 7;
int a[N];
int f[M][N];
int qmi(int a, int k) {
int ret = 1;
while (k) {
if (k & 1) ret = 1ll * ret * a % mod;
a = 1ll * a * a % mod;
k >>= 1;
}
return ret;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
for (int i = 1; i <= n << 1; i++) {
cin >> a[i];
}
sort(a + 1, a + 2 * n + 1);
for (int i = 1; i <= 100; i++) {
int inv = qmi(i, mod - 2);
for (int j = 1; j <= n; j++) {
f[i][j] = (100 + (100ll - i) * f[i][j - 1] % mod) * inv % mod;
}
for (int j = 1; j <= n; j++) {
f[i][j] = (f[i][j] + f[i][j - 1]) % mod;
}
}
int ret = 0;
for (int i = 1; i <= n << 1; i++) {
ret = (ret + f[a[i]][i + 1 >> 1]) % mod;
}
cout << ret;
return 0;
}
参考资料
牛客周赛100讲解:https://www.bilibili.com/video/BV1f2uczGExP/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/18985211