[BJOI2019] 光线
题目大意
设对于任意 \(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;
}