[BJOI2019]光线(DP)

降智了……

当你走头无路的时候就应该知道瞎搞一个DP:

$p[i]$ 表示光射入第 $1$ 块玻璃时,从第 $i$ 块玻璃出去的光量。

$q[i]$ 表示光射入第 $i$ 块玻璃时,从第 $i$ 块玻璃出去的光亮。

为什么是第 $i$ 块呢?因为我们最后只关注 $p[n]$,所以我们关注的反射都是前 $i$ 块射向第 $i+1$ 块(也就是 $q[i]$)和从第 $i+1$ 块射向前 $i$ 块(也就是 $b_{i+1}$)。

初始状态 $p[1]=a_1,q[1]=b_1$。答案为 $p[n]$。

随便画个图得到转移:

$$p[i]=dfrac{p[i-1]a_i}{1-q[i-1]b_i}$$

$$q[i]=b_i+dfrac{q[i-1]a_i^2}{1-q[i-1]b_i}$$

时间复杂度 $O(nlog)$。可以做到 $O(n)$,但是懒得写了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=500050,mod=1000000007,inv100=570000004;
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline int read(){
    int x=0,f=0;char ch=getchar();
    while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return f?-x:x;
}
int n,a[maxn],b[maxn],f[maxn],g[maxn];
inline int add(int x,int y){return x+y<mod?x+y:x+y-mod;}
inline int sub(int x,int y){return x<y?x-y+mod:x-y;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline int qpow(int a,int b){
    int ans=1;
    for(;b;b>>=1,a=mul(a,a)) if(b&1) ans=mul(ans,a);
    return ans;
}
int main(){
    n=read();
    FOR(i,1,n) a[i]=mul(read(),inv100),b[i]=mul(read(),inv100);
    f[1]=a[1];g[1]=b[1];
    FOR(i,2,n){
        int inv=qpow(sub(1,mul(g[i-1],b[i])),mod-2);
        f[i]=mul(mul(f[i-1],a[i]),inv);
        g[i]=add(b[i],mul(mul(mul(a[i],a[i]),g[i-1]),inv));
    }
    printf("%d
",f[n]);
}
View Code
原文地址:https://www.cnblogs.com/1000Suns/p/11203818.html