首页 > 其他分享 >口吃

口吃

时间:2024-09-18 23:24:41浏览次数:1  
标签:frac leq 口吃 1ll cdot int mod

口吃

题目描述

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

标签:frac,leq,口吃,1ll,cdot,int,mod
From: https://www.cnblogs.com/onlyblues/p/18419555

相关文章