[CF712E]Memory and Casinos

280 篇文章 1 订阅
137 篇文章 1 订阅

今天胃痛了一天……待在家里都不知道该做些什么……又不想学习,又不想打球……

看到自己洛谷的任务计划还有那么长,心中又浮起一丝惆怅……

题目

传送门 to luogu

思路

序列问题,直接 猜想是线段树或者分块。二者的共同点:涉及 区间合并。只要有区间合并,就可以随便套。

想到这个就比较简单。全过程分解成多个小区间的方式很唯一嘛。对于每个区间,用 f l , f r f_l,f_r fl,fr 表示,从左(右)端点开始,最终从左(右)端点走出去的概率。

转移便比较简单,以左进左出为例。现在有两个区间 a l , a r a_l,a_r al,ar b l , b r b_l,b_r bl,br ,那么左进左出要么经过了中线(到达过 b b b 部)要么没有。如果经过中线,可能会反复横跳,枚举往返次数,则有
f l = a l + ∑ i = 0 + ∞ ( 1 − a l ) ⋅ b l ⋅ ( a r b l ) i ⋅ ( 1 − a r ) f_l=a_l+\sum_{i=0}^{+\infty}(1-a_l)\cdot b_l\cdot(a_rb_l)^i\cdot(1-a_r) fl=al+i=0+(1al)bl(arbl)i(1ar)

无穷级数大家都会嘛。所以
f l = a l + ( 1 − a l ) ( 1 − a r ) b l 1 − a r b l f_l=a_l+{(1-a_l)(1-a_r)b_l\over 1-a_rb_l} fl=al+1arbl(1al)(1ar)bl

你突然担心起来——如果 a r b l = 1 a_rb_l=1 arbl=1 咋整?此种情形下, a a a 中必然有一个地方是必赢,否则是有从左边出去的可能性的。而题目中保证了获胜概率单调不降,所以 b b b 中应当都为必赢。进而 b l = 0 b_l=0 bl=0 。所以不会有除以零的情况。

复杂度 O ( n log ⁡ n + q log ⁡ n ) \mathcal O(n\log n+q\log n) O(nlogn+qlogn)

代码

#include <cstdio>
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
inline int readint(){
	int a = 0; char c = getchar(), f = 1;
	for(; c<'0'||c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c&&c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}

struct Node{
	double l, r; Node(){}
	Node(double L,double R):l(L),r(R){}
};
Node operator + (const Node &a,const Node &b){
	return Node(
		a.l+(1-a.l)*(1-a.r)*b.l/(1-a.r*b.l),
		b.r+(1-b.r)*(1-b.l)*a.r/(1-a.r*b.l)
	);
}

const int MaxN = 100005;
Node val[MaxN<<1]; int n;
# define id(l,r) (((l)+(r))|((l)!=(r)))
void modify(int qid,double v,int l=1,int r=n){
	if(l == r){
		val[l<<1].l = 1-v; // lose
		val[l<<1].r = v; // win
		return ;
	}
	int mid = (l+r)>>1;
	if(mid < qid) modify(qid,v,mid+1,r);
	else modify(qid,v,l,mid);
	val[id(l,r)] = val[id(l,mid)]
		+ val[id(mid+1,r)]; // pushUp
}
Node query(int ql,int qr,int l=1,int r=n){
	if(ql <= l && r <= qr)
		return val[id(l,r)];
	int mid = (l+r)>>1;
	if(qr <= mid) // only left
		return query(ql,qr,l,mid);
	if(mid < ql) // only right
		return query(ql,qr,mid+1,r);
	return query(ql,qr,l,mid)
		+ query(ql,qr,mid+1,r);
}

int main(){
	n = readint(); int q = readint();
	for(int i=1,a,b; i<=n; ++i){
		a = readint(), b = readint();
		modify(i,1.0*a/b);
	}
	for(int opt,a,b,x; q; --q){
		opt = readint();
		if(opt == 1) x = readint();
		a = readint(), b = readint();
		if(opt == 1)
			modify(x,1.0*a/b);
		if(opt == 2)
			printf("%.10f\n",1-query(a,b).l);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值