LOJ #2263. 「CTSC2017」游戏(倍增+概率与期望)

该博客介绍了如何解决LOJ编号为2263的「CTSC2017」游戏问题,通过运用倍增算法和概率与期望的概念来计算在不同比赛情境下的胜利期望场数。博主讨论了状态转移方程,并指出二维矩阵乘法在解决问题中的应用。最后,分享了实现AC代码。
摘要由CSDN通过智能技术生成

题目

g l , r , c ∈ 0 / 1 , d ∈ 0 / 1 g_{l,r,c\in 0/1,d\in 0/1} gl,r,c0/1,d0/1表示对于小 R R R , 在第 l − 1 l-1 l1场比赛的输赢情况是 c c c,在第 r + 1 r+1 r+1场比赛的输赢情况是 d d d之下的 [ l , r ] [l,r] [l,r]中的胜利期望场数, f l , r , c , d f_{l,r,c,d} fl,r,c,d是在第 l − 1 l-1 l1场比赛的输赢情况是 c c c,在第 r + 1 r+1 r+1场比赛的输赢情况是 d d d的概率。
f a , b , c , d = f a , k , c , e ∗ f k + 1 , b , e , d f_{a,b,c,d} = f_{a,k,c,e} * f_{k+1,b,e,d} fa,b,c,d=fa,k,c,efk+1,b,e,d
g a , b , c , d = f a , k , c , e ∗ g k + 1 , b , e , d + g a , k , c , e ∗ f k + 1 , b , e , d g_{a,b,c,d} = f_{a,k,c,e} * g_{k+1,b,e,d} + g_{a,k,c,e} * f_{k+1,b,e,d} ga,b,c,d=fa,k,c,egk+1,b,e,d+ga,k,c,efk+1,b,e,d
可以发现对于后两维,这就是一个 2 × 2 2 \times 2 2×2矩阵的乘法。(这不重要,重要的是结合律)
所以我们就可以算了。
修改?可以很简单的计算。
至于网上的贝叶斯公式,就是对于 f , g f,g f,g计算的理论依据。
A C   C o d e \rm AC \ Code AC Code

#include<bits/stdc++.h>
#define maxn 200005
#define lim 18
using namespace std;

struct mat{
	double a[2][2];
	mat(double d=0){ a[0][1]=a[1][0]=0,a[0][0]=a[1][1]=d; }
	mat operator *(const mat &B)const{
		mat r;
		for(int i=0;i<2;i++)
			for(int j=0;j<2;j++)
				for(int k=0;k<2;k++)	
					r.a[i][k] += a[i][j] * B.a[j][k];
		return r;
	}
	mat operator +(const mat &B)const{
		mat r;
		for(int i=0;i<2;i++)
			for(int j=0;j<2;j++)
				r.a[i][j] = a[i][j] + B.a[i][j];
		return r;
	}
}f[lim][maxn],s[lim][maxn];

int S[maxn];
set<int>st;
double ask(int l,int r){
	mat t(1),g;int L=l;
	for(int i=lim-1;i>=0;i--)
		if(l+(1<<i)-1 <= r){
			g = t * s[i][l] + g * f[i][l];
			t = t * f[i][l];
			l += (1<<i);
		}
	if(S[r] == -1) return (g.a[S[L-1]][0] + g.a[S[L-1]][1]) / (t.a[S[L-1]][0] + t.a[S[L-1]][1]);
	return g.a[S[L-1]][S[r]] / t.a[S[L-1]][S[r]];
}

int n,m;

int main(){
	freopen("1.in","r",stdin);
	char typ[10];scanf("%d%d%s",&n,&m,typ);
	scanf("%lf",&f[0][1].a[1][1]);f[0][1].a[1][0]=1-f[0][1].a[1][1],s[0][1].a[1][1]=f[0][1].a[1][1];
	for(int i=2;i<=n;i++) 
		scanf("%lf%lf",&f[0][i].a[1][1],&f[0][i].a[0][1]),
		f[0][i].a[1][0] =1-f[0][i].a[1][1], f[0][i].a[0][0] =1-f[0][i].a[0][1],
		s[0][i].a[1][1] = f[0][i].a[1][1] , s[0][i].a[0][1] = f[0][i].a[0][1];
	for(int j=1;j<lim;j++)
		for(int i=1;i+(1<<j)-1<=n;i++)
			f[j][i] = f[j-1][i] * f[j-1][i+(1<<j-1)] ,
			s[j][i] = s[j-1][i] * f[j-1][i+(1<<j-1)] + f[j-1][i] * s[j-1][i+(1<<j-1)];
	st.insert(0),st.insert(n);
	memset(S,-1,sizeof S) , S[0] = 1;
	double ans = ask(1,n);
	for(int i,c;m--;){
		scanf("%s",typ);
		if(typ[0] == 'a'){
			scanf("%d%d",&i,&c);
			set<int>::iterator r = st.lower_bound(i) , l = r; l--; 
			ans -= ask(*l+1,*r);
			S[i] = c;
			ans += ask(*l+1,i) + ask(i+1,*r);
			st.insert(i);
		}
		else{
			scanf("%d",&i);
			if(i != n) st.erase(i);
			set<int>::iterator r = st.lower_bound(i) , l = r ; l--;
			ans -= ask(*l+1,i) + ask(i+1,*r);
			S[i] = -1;
			ans += ask(*l+1,*r);
		}
		printf("%.6lf\n",ans);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值