[BJOI2019] 光线

发布时间 2023-08-23 19:56:10作者: -白简-

题目大意

设对于任意 \(x\),有 \(x \times a_i\%\) 单位的光会穿过它,有 \(x \times b_i\%\) 的会被反射回去。
现在 \(n\) 层玻璃叠在一起,有 \(1\) 单位的光打到第 \(1\) 层玻璃上,那么有多少单位的光能穿过所有 \(n\) 层玻璃呢?

思路

\(f_i\) 表示第 \(i\) 块玻璃向下发出的光线,\(g_i\) 表示第 \(i\) 块玻璃向上发出的光线。

考虑一块玻璃向下发出的光线,不只由上面玻璃传来,也可能是下面玻璃射过来被当前玻璃反射。

那么我们有

\[f_i=f_{i-1}\times a_i+g_{i+1}\times b_i \]

\[g_i=f_{i-1}\times b_i +g_{i+1}\times a_i \]

上面的方程里还有 \(g_{i+1}\),无法转移,考虑消去它。

我们可以认为 \(g_{n+1}=0\),我们还知道

\[f_{n}=f_{n-1}\times a_n \]

\[g_n=f_{n-1}\times b_n \]

那么对于 \(f_{n-1}\)\(g_{n-1}\) 的方程,我们能消去 \(g_n\),得到

\[f_{n-1}=f_{n-2}\times a_{n-1}+(f_{n-1}\times b_n)b_{n-1} \]

\[g_{n-1}=f_{n-2}\times b_{n-1}+(f_{n-1}\times b_n)a_{n-1} \]

我们可以考虑迭代的思想消去 \(g\)

\(F_i=\dfrac{f_i}{f_{i-1}},G_{i} =\dfrac{g_i}{f_{i-1}}\),即 \(f_i\)\(g_i\) 分别是 \(f_{i-1}\) 的多少倍。

已知 \(F_n=a_n,G_n=b_n\),我们可以倒序求出 \(F\)\(G\)

对于 \(F\),有

\[f_i=f_{i-1}\times a_i+g_{i+1}\times b_i \]

把最上面的式子等号两边都除以一个 \(f_{i-1}\),得到

\[F_i=\dfrac{f_i}{f_{i-1}}=a_i+\dfrac{g_{i+1} \times b_i}{f_{i-1}} \]

分子分母都乘一个 \(f_i\),再把 \(G_i\) 代入,得

\[F_i=a_i+G_{i+1}\times b_i \times F_i \]

所以有

\[F_i=\dfrac{a_i}{1-G_{i+1}\times b_i} \]

对于 \(G\),有

\[g_i=f_{i-1}\times b_i + g_{i+1}\times a_i \]

\[G_i=\dfrac{g_i}{f_{i-1}}=b_i+\dfrac{g_{i+1}\times a_i}{f_{i-1}} \]

分子分母都乘一个 \(f_i\),再把 \(F_i\) 代入,得

\[G_i=b_i+G_{i+1}\times a_i \times F_i \]

由此可以转移,递推求出 \(f_n\),边界 \(f_0=1\)

\[f_i = f_{i-1} \times F_i \]

#include <bits/stdc++.h>

using namespace std;

#define int long long

const int N = 500500;
const int Mod = 1e9 + 7;

long long Pow(long long a ,long long b) {
    long long res = 1 ;
    long long base = a;
    while(b) {
   	    if(b & 1)
   		    res = res * base % Mod;
   	    base = base * base % Mod;
   	    b >>= 1;
   }
   return res % Mod;
}

long long Inv(long long x) {
    return Pow(x,Mod - 2);
}

int n;
int a[N],b[N];

int f[N],g[N];
int F[N],G[N];

signed main() {
    ios::sync_with_stdio(false);

    cin >> n;
    for(int i = 1;i <= n; i++) {
        cin >> a[i] >> b[i];
        a[i] = 1ll * a[i] * Inv(100) % Mod;
        b[i] = 1ll * b[i] * Inv(100) % Mod;
    }

    F[n] = a[n];
    G[n] = b[n];

    for(int i = n - 1;i >= 1; i--) {
        F[i] = 1ll * a[i] * Inv(1 - 1ll * G[i + 1] * b[i] % Mod) % Mod;
        G[i] = 1ll * (1ll * b[i] + G[i + 1] * a[i] % Mod * F[i] % Mod) % Mod;
    }
    
    f[0] = 1;
    
    for(int i = 1;i <= n; i++)
        f[i] = 1ll * f[i - 1] * F[i] % Mod;

    cout << (f[n] + 10 * Mod) % Mod << "\n";
    return 0;
}