[BJOI2019] 光线

题目

有点奇怪的题目

我们设(dp_i)表示经过(1)单位的光经过前(i)面镜子后变成了多少,也就是前(i)面镜子整体的透光率

(f_i)表示倒着(即从第(i)面镜子到第(1)面镜子)射入(1)单位的光,反射出去的光为多少,或者说是这(i)面镜子整体的反光率

我们考虑如何求出(dp_i)(f_i)

先考虑(dp_i)

首先有(dp_{i-1})的光直接过来了,这些光有(a_i)直接穿过,为(dp_{i-1} imes a_i)

还有(b_i)被反射回去,也就是是有(dp_{i-1} imes b_i)的光倒着穿过了前(i)面镜子,反射回来的光是(dp_{i-1} imes b_i imes f_{i-1}),这些光又有(a_i)穿过第(i)面镜子

如果往下继续写,我们会发现得到这样一个柿子

[dp_{i}=a_isum_{j=0}^{infty}dp_{i-1}(f_{i-1}b_i)^j ]

对后面求一下和

[dp_{i}=frac{a_i imes dp_{i-1}}{1-f_{i-1}b_i} ]

再来考虑(f_i)

首先有(1)的光射了过来,有(b_i)直接被反射回去,这里是(b_i)

但是有(a_i)的光射了进去,所以有(f_{i-1} imes a_i)的光被反射回来,这些光在经过第(i)面镜子,反射出来的是(f_{i-1} imes a_i^2)

继续往下写,我们得到了这样的柿子

[f_i=b_i+sum_{j=0}^{infty}a_i^2f_{i-1}(f_{i-1}b_i)^j=b_i+frac{f_{i-1} imes a_{i}^2}{1-f_{i-1}b_i} ]

于是我们递推就好了,答案就是(dp_n)

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define re register
const int maxn=5e5+5;
const int inv=570000004;
const int mod=1e9+7;
inline int read() {
	char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
int n;
int dp[maxn],a[maxn],b[maxn],f[maxn];
inline int ksm(int a,int b) {
	int S=1;
	while(b) {if(b&1) S=(1ll*S*a)%mod;b>>=1;a=(1ll*a*a)%mod;}
	return S;
}
int main() {
	n=read();
	for(re int i=1;i<=n;i++) a[i]=read(),b[i]=read();
	for(re int i=1;i<=n;i++) a[i]=(1ll*a[i]*inv)%mod,b[i]=(1ll*b[i]*inv)%mod;
	dp[1]=a[1],f[1]=b[1];
	for(re int i=2;i<=n;i++) {
		int Inv=ksm(1-1ll*b[i]*f[i-1]%mod+mod,mod-2);
		f[i]=(1ll*a[i]*a[i]%mod*f[i-1]%mod*Inv%mod);
		f[i]=(f[i]+b[i])%mod;
		dp[i]=(1ll*a[i]*dp[i-1]%mod*Inv)%mod;
	}
	printf("%d
",dp[n]);
	return 0;
}
原文地址:https://www.cnblogs.com/asuldb/p/10751131.html