LOJ 3093 「BJOI2019」光线——数学+思路

题目:https://loj.ac/problem/3093

考虑经过种种反射,最终射下去的光线总和。往下的光线就是这个总和 * a[ i ] 。

比如只有两层的话,设射到第二层的光线是 lst ,那么 \( lst' = ( lst + lst*b[2]*b[1] + lst*(b[2]*b[1])^2 + ... )*a[2] \)

考虑令 f[ i ] 表示 “从第 i 层下面射上来的单位光线在考虑第 i+1 层反射的情况下射下去的值” 。

\( f[i] = b[i]+a[i]*f[i-1]*a[i] + ( b[i]+a[i]*f[i-1]*a[i] ) * b[i+1] * ( b[i]+a[i]*f[i-1]*a[i]) + ... \) 

其中 \( b[i]+a[i]*f[i-1]*a[i] \) 就是一次反射下去的光线和。设 \( x = b[i]+a[i]*f[i-1]*a[i] \) 

式子也就是 \( f[i]=x+x*b[i+1]*x + ... = x \sum\limits_{k=0}^{\infty}(b[i+1]*x)^k \) 

然后令 lst 表示透过第 i-1 层的光线,lst' 表示透过第 i 层的光线,就有 \( lst' = (lst + lst*b[i]*f[i-1])*a[i] \)

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
const int N=5e5+5,mod=1e9+7;
int upt(int x){while(x>=mod)x-=mod;while(x<0)x+=mod;return x;}
int pw(int x,int k)
{int ret=1;while(k){if(k&1)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=1;}return ret;}

int n,a[N],b[N],f[N],ans;
int main()
{
  n=rdn(); int iv=pw(100,mod-2);
  for(int i=1;i<=n;i++)
    {
      a[i]=(ll)rdn()*iv%mod;
      b[i]=(ll)rdn()*iv%mod;
    }
  for(int i=1;i<=n;i++)
    {
      int x=(b[i]+(ll)a[i]*f[i-1]%mod*a[i])%mod;
      f[i]=(ll)x*pw(upt(1-(ll)x*b[i+1]%mod),mod-2)%mod;
    }
  ans=a[1];
  for(int i=2;i<=n;i++)
    ans=(1+(ll)b[i]*f[i-1])%mod*ans%mod*a[i]%mod;
  printf("%d\n",ans);
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/Narh/p/10941818.html