[BJOI2019] 光线
题解
题解
\(dp\)
其实就是无限项的等比数列求和
无线项等比数列求和公式就是\(\frac{首项}{1-公比}\)
然后我们对于这道题
\(p1_i\)表示透光率,\(p2_i\)表示反射率
可以设\(f_i\)表示从第\(i\)号玻璃射出的光线数量
\(g_i\)表示从玻璃\(i\)下方射入1单位的光线最终反射回\(i\)的下方的光线的数量
那么可以发现\(g_i=p1_i^2\times (p2_{i-1}+g_{i-1}) + p1_i^2\times (p2_{i-1}+g_{i-1}) \times p2_i \times (p2_{i-1} + g_{i-1})+...\)
所以\(g_i=\frac{p1_i^2\times (p2_{i-1}+g_{i-1})}{1-p2_i\times (p2_{i-1} + g_{i-1})}\)
\(f_i = f_{i-1}\times p1_i + f_{i-1}\times p1_i\times p2_{i+1}\times (p2_i + g_i))\)
所以\(f_i=\frac{f_{i-1}+p1_i}{1-p2_{i+1}\times (p2_i+g_i)}\)
答案就是\(f_n\)
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
# define LL long long
const int M = 500005 ;
const int mod = 1e9 + 7 ;
using namespace std ;
inline int read() {
char c = getchar() ; int x = 0 , w = 1 ;
while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
return x*w ;
}
int n , inv100 ;
LL p1[M] , p2[M] , f[M] , g[M] ;
inline int Fpw(int Base , int k) {
int temp = 1 ;
while(k) {
if(k & 1) temp = 1LL * temp * Base % mod ;
Base = 1LL * Base * Base % mod ; k >>= 1 ;
}
return temp ;
}
inline int Inv(int x) {
x = (x % mod + mod) % mod ;
return Fpw(x , mod - 2) ;
}
int main() {
n = read() ; inv100 = Inv(100) ;
for(int i = 1 ; i <= n ; i ++) {
p1[i] = read() ; p2[i] = read() ;
p1[i] = 1LL * p1[i] * inv100 % mod ;
p2[i] = 1LL * p2[i] * inv100 % mod ;
}
f[0] = 1 ; p1[0] = 1 ; g[0] = 0 ;
for(int i = 1 ; i <= n ; i ++) {
g[i] = p1[i] * p1[i] % mod * (p2[i - 1] + g[i - 1]) % mod * Inv( ( 1 - p2[i] * ( p2[i - 1] + g[i - 1] ) % mod ) % mod ) % mod ;
g[i] = (g[i] + mod) % mod ;
f[i] = f[i - 1] * p1[i] % mod * Inv( ( 1 - p2[i + 1] * ( p2[i] + g[i] ) % mod ) % mod ) % mod ;
f[i] = (f[i] + mod) % mod ;
}
printf("%lld\n",f[n]) ;
return 0 ;
}