[BJOI]光线 可达2257

题目描述

当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收。

设对于任意 �x,有 �×��%x×ai​% 单位的光会穿过它,有 �×��%x×bi​% 的会被反射回去。 现在 �n 层玻璃叠在一起,有 11 单位的光打到第 11 层玻璃上,那么有多少单位的光能穿过所有 �n 层玻璃呢?

输入格式

第一行一个正整数 �n,表示玻璃层数。 接下来 �n 行,每行两个非负整数 ��,��ai​,bi​,表示第 �i 层玻璃的透光率和反射率。

输出格式

输出一行一个整数,表示穿透所有玻璃的光对 109+7109+7 取模的结果。 可以证明,答案一定为有理数。设答案为 �/�a/b ( �a 和 �b 是互质的正整数),你输出的答案为 �x,你需要保证 �≡�� (mod 109+7)a≡bx (mod 109+7)。

样例 #1

样例输入 #1

2
50 20
80 5

Copy

样例输出 #1

858585865

Copy

样例 #2

样例输入 #2

3
1 2
3 4
5 6

Copy

样例输出 #2

843334849

Copy

提示

样例1解释: 

5cbc74abe6af5.png

 如图,光线从左上角打进来,有 0.50.5 单位的光穿过第 11 层玻璃,有 0.20.2 单位的光被反射回去。这 0.50.5 单位的光有 0.40.4 单位穿过第 22 层玻璃,有 0.0250.025 单位的光被反射回去。这 0.0250.025 单位的光有 0.01250.0125 单位穿过第 11 层玻璃,有 0.0050.005 单位的光被反射回去。这 0.0050.005 单位的光有 0.0040.004 单位穿过第 22 层玻璃……于是,穿过两层玻璃的光一共有0.40404...=40/990.40404...=40/99 单位。在模 109+7109+7 意义下等于 858585865858585865。

数据范围: 对于 5%5% 的数据,�=1n=1; 对于 20%20% 的数据,�≤2n≤2; 对于 30%30% 的数据,�≤3n≤3; 对于 50%50% 的数据,�≤100n≤100; 对于 70%70% 的数据,�≤3000n≤3000; 对于 100%100% 的数据,�≤5×105n≤5×105,1≤��≤1001≤ai​≤100,0≤��≤990≤bi​≤99,1≤��+��≤1001≤ai​+bi​≤100。

每组 ��ai​ 和 ��bi​ 在满足上述限制的整数中随机生成。

解析::::

说实话,一读题第一反应竟是“bjoi就这?”但是,看完样例的分析我傻了,是我理解错题意了······赶紧从头又分析了一遍,感觉没问题了,便开始敲代码,结果敲了半个小时发现,好像还没有完全理解,再一次回头分析了一下样例(这提醒我们,一定要审好题,理解题意后在动手,要不然就会像我一样,浪费时间),发现第一面和最后一面的反射率是不一样的,我竟然还天真的认为反射率是一样的,不过透光率是一样的(经过计算可知),所以呢,这样就很容易了,只需要维护两个变量即可:

1、光从第 1 面玻璃射入时的透光率。

2、光从第 i 面玻璃射入时的反射率。

��=��−1��∑�=0∞(��−1��)�pi​=pi−1​ai​∑k=0∞​(qi−1​bi​)k

��=��+��−1��2∑�=0∞(��−1��)�qi​=bi​+qi−1​ai2​∑k=0∞​(qi−1​bi​)k

其中,还可以进一步优化:带有**∑�=0∞��∑k=0∞​ak的形式,当∣�∣∣a∣<1时,它等于11−�1−a1​**

所以:

��=��−1��1−��−1��Pi​=1−Qi−1​bi​Pi−1​ai​​

��=��+��−1��21−��−1��Qi​=bi​+1−Qi−1​bi​Qi−1​ai2​​

可以先计算出**11−��−1��1−Qi−1​bi​1​**简化计算

最后,贴上代码:

#include<bits/stdc++.h>
#define N 1000010
#define int long long
#define INF 0x3f3f3f3f
const int Mod = 1e9 + 7;
const int Inv100 = 570000004;//(pow(100, Mod - 2));
#define ld long double
#define M 1010
#define R register int
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
  if(ch=='-') f=-1;
  ch=getchar();
}
while(isdigit(ch)){
  x=(x<<3)+(x<<1)+ch-'0';
  ch=getchar();
}
return x*=f;
}

inline void write(int x){
if(x<0){
  putchar('-');
  x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
int n;
int p, q;//p:前 i 面玻璃按顺序叠在一起后,光从第 1 面玻璃射入时的透光率。
//q:前 i 面玻璃按顺序叠在一起后,光从第 i 面玻璃射入时的反射率。
inline int Inv(int x){
int a = 1;
for (int i = Mod - 2; i; i >>= 1){
  if(i&1) a = a * x % Mod;
  x = x * x % Mod;
}
return a;
}
signed main(){
n = read();
p = 1, q = 0;
while(n--){
  int a = read(), b = read();
  a = a * Inv100 % Mod;
  b = b * Inv100 % Mod;
  int d = Inv(1 - q * b % Mod + Mod) % Mod;
  q = (b + a * a % Mod * q % Mod * d) % Mod;
  p = p * a % Mod * d % Mod;
}
write(p);
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值