luogu P5323 [BJOI2019]光线

传送门

先考虑\(n=1\)的情况不是输入数据都告诉你了吗

然后考虑\(n=2\),可以光线是在弹来弹去的废话,然后射出去的光线是个等比数列求和的形式,也就是\(x_1\sum_{i=1}^{\infty} d^i=x_1\frac{1}{1-d}\),然后弹回去的光线第一个光线就是\(b_i\),然后后面也是等比数列求和,算一下就好了

\(n>2\),我们做完\(n-1\)后,可以把刚刚算过的玻璃看成一块,因为已经知道会射出去多少以及弹回去多少,然后就变成了\(n=2\),那么递推做即可

我写的是倒推,好像顺推也可以qwq

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#include<ctime>
#include<queue>
#include<map>
#include<set>
#define LL long long
#define db double

using namespace std;
const int N=5e5+10,mod=1e9+7,pc=570000004;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
int fpow(int a,int b){int an=1;while(b){if(b&1) an=1ll*an*a%mod;a=1ll*a*a%mod,b>>=1;} return an;}
int inv(int a){return fpow(a,mod-2);}
int n,a[N],b[N],f[2],g[2];

int main()
{
    n=rd();
    for(int i=1;i<=n;++i) a[i]=1ll*rd()*pc%mod,b[i]=1ll*rd()*pc%mod;
    int nw=1,la=0;
    f[la]=a[n],g[la]=b[n];
    for(int i=n-1;i;--i)
    {
        g[nw]=b[i];
        int lt=a[i],s1,s2,t1,t2,dd;
        s1=1ll*lt*f[la]%mod,lt=1ll*lt*g[la]%mod;
        t1=1ll*lt*a[i]%mod,lt=1ll*lt*b[i]%mod;
        s2=1ll*lt*f[la]%mod,lt=1ll*lt*g[la]%mod;
        t2=1ll*lt*a[i]%mod;
        dd=1ll*s2*inv(s1)%mod,f[nw]=1ll*s1*inv(mod+1-dd)%mod;
        dd=1ll*t2*inv(t1)%mod,g[nw]=(g[nw]+1ll*t1*inv(mod+1-dd))%mod;
        nw^=1,la^=1;
    }
    printf("%d\n",f[la]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/smyjr/p/10770560.html