CF712E Memory and Casinos

一、题目

点此看题

二、解法

这道题正向走不通,要反向做,设 d p [ i ] dp[i] dp[i] i i i到终点的概率:
f i = f i − 1 × ( 1 − p i ) + f i + 1 × p i f_i=f_{i-1}\times(1-p_i)+f_{i+1}\times p_i fi=fi1×(1pi)+fi+1×pi f i − f i − 1 = p i ( f i + 1 − f i ) f_i-f_{i-1}=p_i(f_{i+1}-f_i) fifi1=pi(fi+1fi) g i = f i − f i − 1 g_i=f_i-f_{i-1} gi=fifi1,那么: g i = p i ( g i + 1 + g i ) g_i=p_i(g_{i+1}+g_i) gi=pi(gi+1+gi),就可以得到:
g i + 1 = 1 − p i p i g i g_{i+1}=\frac{1-p_i}{p_i}g_i gi+1=pi1pigi因为 f n = 1 , f 0 = 0 f_n=1,f_0=0 fn=1,f0=0,所以 ∑ i = 1 n g i = 1 \sum_{i=1}^ng_i=1 i=1ngi=1,设 t i = 1 − p i p i t_i=\frac{1-p_i}{p_i} ti=pi1pi.,上面是用 [ 1 , n ] [1,n] [1,n]来推的,这里需要是 [ l , r + 1 ] [l,r+1] [l,r+1]
g l ( 1 + t l + t l t l + 1 . . . . . + t l . . t r ) = 1 g_l(1+t_l+t_lt_{l+1}.....+t_l..t_r)=1 gl(1+tl+tltl+1.....+tl..tr)=1那么我们维护下这个系数,就可以直接算答案了。

2020-06-18: 以前做过这题的,但是考同样的题没做出来,主要是定义问题,自闭了。

#include <cstdio>
#define db double
const int M = 400005;
int read()
{
    int x=0,flag=1;
    char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,m;db p[M],x[M],y[M];
void up(int i)
{
    x[i]=x[i<<1]*x[i<<1|1];
    y[i]=y[i<<1]+y[i<<1|1]*x[i<<1];
}
void ins(int i,int l,int r,int id)
{
    if(l==r)
    {
        x[i]=y[i]=p[id];
        return ;
    }
    int mid=(l+r)>>1;
    if(mid>=id) ins(i<<1,l,mid,id);
    else ins(i<<1|1,mid+1,r,id);
    up(i);
}
db ask1(int i,int l,int r,int L,int R)
{
    if(l>R || L>r) return 1;
    if(L<=l && r<=R) return x[i];
    int mid=(l+r)>>1;
    return ask1(i<<1,l,mid,L,R)*ask1(i<<1|1,mid+1,r,L,R);
}
db ask2(int i,int l,int r,int L,int R)
{
    if(l>R || L>r) return 0;
    if(L<=l && r<=R) return y[i];
    int mid=(l+r)>>1;db ret=0;
    ret=ask2(i<<1,l,mid,L,R);
    if(mid<R) ret+=ask1(i<<1,l,mid,L,R)*ask2(i<<1|1,mid+1,r,L,R);
    return ret;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
    {
        int u=read(),v=read();
        p[i]=1.0*(v-u)/u;
        ins(1,1,n,i);
    }
    while(m--)
    {
        int op=read();
        if(op==1)
        {
            int i=read(),u=read(),v=read();
            p[i]=1.0*(v-u)/u;
            ins(1,1,n,i);
        }
        if(op==2)
        {
            int l=read(),r=read();
            printf("%.5lf\n",1.0/(ask2(1,1,n,l,r)+1.0));
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值