口吃
口吃
题目描述
Zaoly 要讲一句话,这句话有 n 个字,他要一个字一个字讲出来。奈何 Zaoly 口吃:
- 讲到第 1 个字时,下一个要讲的字有 $\frac{a_1}{a_1+b_1}$ 的概率前进到第 2 个字,有 $\frac{b_1}{a_1+b_1}$ 的概率仍是第 1 个字。
- 讲到第 $i$ $(2 \leq i \leq n−1)$ 个字时,下一个要讲的字有 $\frac{a_{i}^{2}}{a_{i}^{2}+2 a_i \cdot b_i + b_{i}^{2}}$ 的概率前进到第 $i+1$ 个字,有 $\frac{2 a_i \cdot b_i}{a_{i}^{2}+2 a_i \cdot b_i + b_{i}^{2}}$ 的概率仍是第 $i$ 个字,有 $\frac{b_{i}^{2}}{a_{i}^{2}+2 a_i \cdot b_i + b_{i}^{2}}$ 的概率倒退到第 $i−1$ 个字。
- 讲到第 $n$ 个字时,讲话完毕,停止讲话。
直到讲话完毕,Zaoly 总共讲出的字数的期望是多少?
输入描述:
第一行输入一个整数 $n$ $(2 \leq n \leq 10^5)$,表示这句话有 $n$ 个字。
第二行输入 $n−1$ 个数 $a_1, a_2, \ldots, a_{n−1}$ $(1 \leq a_i \leq 10^9)$ 表示数组。
第三行输入 $n−1$ 个数 $b_1, b_2, \ldots, b_{n−1}$ $(1 \leq b_i \leq 10^9)$ 表示数组。
保证对于所有的 $1 \leq i \leq n−1$,都满足 $a_i + b_i = 10^9 +7$。
输出描述:
输出总共讲出的字数的期望。
可以证明答案可以表示为一个不可约分数 $\frac{p}{q}$,为了避免精度问题,请直接输出整数 $( p \cdot q^{−1} \bmod M)$ 作为答案,其中 $M=10^9+7$,$q^{−1}$ 是满足 $q \times q^{−1} \equiv 1 \pmod{M}$ 的整数。
示例1
输入
2
1
1
输出
3
说明
说完第一个字后,有 $1/2$ 的概率直接前进到下一个字,有 $1/4$ 的概率多讲一个字,有 $1/8$ 的概率多讲两个字 $\ldots \ldots$
说出总字数的期望为 $1 + \frac{1}{2} \times 1 + \frac{1}{4} \times 2 + \frac{1}{8} \times 3 + \frac{1}{16} \times 4 + \cdots = 3$。
示例2
输入
3
1 1
1 1
输出
9
示例3
输入
6
1 2 3 4 5
5 4 3 2 1
输出
800000096
解题思路
一开始往贡献法的思路想没做出来,dp 也不会。这 dp 的定义还挺难想到的,定义 $f(i)$ 表示从第 $i$ 个字开始读的期望值,转移方程就是$$f(i) = \frac{a_i^2}{(a_i+b_i)^2} \cdot f(i+1) + \frac{2a_ib_i}{(a_i+b_i)^2} \cdot f(i) + \frac{b_i^2}{(a_i+b_i)^2} \cdot f(i-1) + 1$$
容易看出这个转移是存在环的。注意到读第 $1$ 个字是不会往前退的,此时有
\begin{align*}
&f(1) = \frac{a_1}{a_1+b_1} \cdot f(2) + \frac{b_1}{a_1+b_1} \cdot f(1) + 1 \\
\Rightarrow &f(1) = f(2) + \frac{a_1+b_1}{a_1}
\end{align*}
对于 $f(2)$ 就有
\begin{align*}
f(2) &= \frac{a_2^2}{(a_2+b_2)^2} \cdot f(3) + \frac{2a_2b_2}{(a_2+b_2)^2} \cdot f(2) + \frac{b_2^2}{(a_2+b_2)^2} \cdot f(1) + 1 \\
&= \frac{a_2^2}{(a_2+b_2)^2} \cdot f(3) + \frac{2a_2b_2}{(a_2+b_2)^2} \cdot f(2) + \frac{b_2^2}{(a_2+b_2)^2} \cdot \left(f(2) + \frac{a_2+b_2}{a_2}\right) + 1 \\
\Rightarrow f(2) &= \frac{a_2^2}{a_2^2 + b_2^2 - b_2^2 \cdot 1} \cdot f(3) + \frac{b_2^2 \cdot \frac{a_1+b_1}{a_1} + (a_2+b_2)^2}{a_2^2 + b_2^2 - b_2^2 \cdot 1}
\end{align*}
这样就可以消去环,进一步推导可以发现转移方程都是 $f(i) = x_i \cdot f(i+1) + y_i$ 的形式。其中 $x_i = \frac{a_i^2}{a_i^2 + b_i^2 - b_i^2 \cdot x_{i-1}}$,$y_i = \frac{b_i^2 \cdot y_{i-1} + (a_i+b_i)^2}{a_i^2 + b_i^2 - b_i^2 \cdot x_{i-1}}$,初始时 $x_1 = 1$,$y_1 = \frac{a_1+b_1}{a_1}$。
由于 $f(n) = 1$,因此我们可以先计算出所有的 $x_i$ 和 $y_i$,然后倒着 dp 依次求出 $f(i)$。
AC 代码如下,时间复杂度为 $O(n \log{M})$:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 5, mod = 1e9 + 7;
int a[N], b[N];
int x[N], y[N];
int f[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; i++) {
cin >> a[i];
}
for (int i = 1; i < n; i++) {
cin >> b[i];
}
x[1] = 1, y[1] = LL(a[1] + b[1]) * qmi(a[1], mod - 2) % mod;
for (int i = 2; i < n; i++) {
int t = qmi((1ll * a[i] * a[i] + 1ll * b[i] * b[i] - 1ll * b[i] * b[i] % mod * x[i - 1]) % mod, mod - 2);
x[i] = 1ll * a[i] * a[i] % mod * t % mod;
y[i] = (1ll * b[i] * b[i] % mod * y[i - 1] + LL(a[i] + b[i]) * (a[i] + b[i])) % mod * t % mod;
}
f[n] = 1;
for (int i = n - 1; i; i--) {
f[i] = (1ll * x[i] * f[i + 1] + y[i]) % mod;
}
cout << f[1];
return 0;
}
参考资料
牛客周赛60题目讲解:https://www.bilibili.com/video/BV1BR4SeYEdi?p=5