[UOJ299][CTSC2017] 游戏
【CTSC2017】游戲
problem
UOJ299
solution
定義 Xi:X_i:Xi?: 當前已知條件第 iii 局的狀態 1/01/01/0(勝/敗)。
將 Xi=CiX_i=C_iXi?=Ci? 記為事件 AiA_iAi?。
假設現在已知條件共有 sss 個,即:第 k1~sk_{1\sim s}k1~s? 局的勝負狀態。
期望不妨拆成求和每一局獲勝的概率。
那么答案為 ∑i=1nP(Xi=1∣Ak1Ak2...Aks)\sum_{i=1}^nP(X_i=1\Big|A_{k_1}A_{k_2}...A_{ks})∑i=1n?P(Xi?=1∣∣∣?Ak1??Ak2??...Aks?)
P(Xi=1∣Ak1Ak2...Aks)=P(Xi=1?Ak1...Aks)P(Ak1...Aks)P(X_i=1\Big|A_{k_1}A_{k_2}...A_{ks})=\frac{P(X_i=1·A_{k_1}...A_{k_s})}{P(A_{k_1}...A_{k_s})}P(Xi?=1∣∣∣?Ak1??Ak2??...Aks?)=P(Ak1??...Aks??)P(Xi?=1?Ak1??...Aks??)?
P(Ak1...Aks)=P(Ak1)P(Ak2∣Ak1)P(Ak3∣Ak1Ak2)...P(Aks∣Ak1...Aks?1)P(A_{k_1}...A_{k_s})=P(A_{k_1})P(A_{k_2}|A_{k_1})P(A_{k_3}|A_{k_1}A_{k_2})...P(A_{k_s}|A_{k_1}...A_{k_{s-1}})P(Ak1??...Aks??)=P(Ak1??)P(Ak2??∣Ak1??)P(Ak3??∣Ak1??Ak2??)...P(Aks??∣Ak1??...Aks?1??)
因為每一局的勝負概率只和上一局有關,所以 P(Ak3∣Ak1Ak2)=P(Ak3∣Ak2)P(A_{k_3}|A_{k_1}A_{k_2})=P(A_{k_3}|A_{k_2})P(Ak3??∣Ak1??Ak2??)=P(Ak3??∣Ak2??)
即,P(Ak1...Aks)=P(Ak1)P(Ak2∣Ak1)P(Ak3∣Ak2)...P(Aks∣Aks?1)P(A_{k_1}...A_{k_s})=P(A_{k_1})P(A_{k_2}|A_{k_1})P(A_{k_3}|A_{k_2})...P(A_{k_s}|A_{k_{s-1}})P(Ak1??...Aks??)=P(Ak1??)P(Ak2??∣Ak1??)P(Ak3??∣Ak2??)...P(Aks??∣Aks?1??)
假設 k1<k2<...<kj<i<kj+1<...<ksk_1<k_2<...<k_j<i<k_{j+1}<...<k_sk1?<k2?<...<kj?<i<kj+1?<...<ks?
類似地,P(Xi=1Ak1...Aks)=P(Ak1)...P(Akj∣Xi=1)P(Xi=1∣Akj+1)...P(Aks∣Aks?1)P(X_i=1A_{k_1}...A_{k_s})=P(A_{k_1})...P(A_{k_j}|X_i=1)P(X_i=1|A_{k_{j+1}})...P(A_{k_s}|A_{k_{s-1}})P(Xi?=1Ak1??...Aks??)=P(Ak1??)...P(Akj??∣Xi?=1)P(Xi?=1∣Akj+1??)...P(Aks??∣Aks?1??)
所以 P(Xi=1∣Ak1Ak2...Aks)=P(Akj∣Xi=1)P(Xi=1∣Akj+1)P(Akj+1∣Akj)P(X_i=1\Big|A_{k_1}A_{k_2}...A_{ks})=\frac{P(A_{k_j}|X_i=1)P(X_i=1|A_{k_{j+1}})}{P(A_{k_{j+1}}|A_{k_j})}P(Xi?=1∣∣∣?Ak1??Ak2??...Aks?)=P(Akj+1??∣Akj??)P(Akj??∣Xi?=1)P(Xi?=1∣Akj+1??)?
答案為 ∑i=1nP(Akj∣Xi=1)P(Xi=1∣Akj+1)P(Akj+1∣Akj)\sum_{i=1}^n\frac{P(A_{k_j}|X_i=1)P(X_i=1|A_{k_{j+1}})}{P(A_{k_{j+1}}|A_{k_j})}∑i=1n?P(Akj+1??∣Akj??)P(Akj??∣Xi?=1)P(Xi?=1∣Akj+1??)?
也就是說,已知結果將 nnn 局游戲劃分成了若干段區間,每段的貢獻計算的先決條件都是一樣的。
也就是說每個區間的答案為 ∑i=kj+1i=kj+1?1P(Akj∣Xi=1)P(Xi=1∣Akj+1)P(Akj+1∣Akj)\sum_{i=k_j+1}^{i=k_{j+1}-1}\frac{P(A_{k_j}|X_i=1)P(X_i=1|A_{k_{j+1}})}{P(A_{k_{j+1}}|A_{k_j})}∑i=kj?+1i=kj+1??1?P(Akj+1??∣Akj??)P(Akj??∣Xi?=1)P(Xi?=1∣Akj+1??)?
設 Q(r∣l):Q(r|l):Q(r∣l): 第 lll 局 RRR 贏的情況下,第 rrr 局 RRR 贏的概率,~l\sim l~l 則表示第 lll 局 RRR 輸。
顯然有,Q(l+1∣l)=p[l+1]Q(l+1\Big|l)=p[l+1]Q(l+1∣∣∣?l)=p[l+1],再考慮計算 Q(l+2∣l)Q(l+2\Big|l)Q(l+2∣∣∣?l)。
Q(l+2∣l)=Q(l+2∣l+1)?Q(l+1∣l)+Q(l+2∣~(l+1))?Q(~(l+1)∣l)=p[l+2]?p[l+1]+q[l+2]?(1?p[l+1])Q(l+2\Big|l)=Q(l+2\Big|l+1)·Q(l+1\Big|l)+Q(l+2\Big|\sim(l+1))·Q(\sim(l+1)\Big|l)\\=p[l+2]·p[l+1]+q[l+2]·(1-p[l+1]) Q(l+2∣∣∣?l)=Q(l+2∣∣∣?l+1)?Q(l+1∣∣∣?l)+Q(l+2∣∣∣?~(l+1))?Q(~(l+1)∣∣∣?l)=p[l+2]?p[l+1]+q[l+2]?(1?p[l+1])
同理可計算出,Q(l+2∣~l),Q(~(l+2)∣l),Q(~(l+2)∣~l)Q(l+2\Big|\sim l),Q(\sim (l+2)\Big|l),Q(\sim (l+2)\Big|\sim l)Q(l+2∣∣∣?~l),Q(~(l+2)∣∣∣?l),Q(~(l+2)∣∣∣?~l)
發現,這其實是兩個矩陣相乘的結果,即 fl+1?fl+2f_{l+1}·f_{l+2}fl+1??fl+2?
fi=[1?qiqi1?pipi]f_{i}=\begin{bmatrix}1-q_i\quad\quad q_i\\1-p_i\quad\quad p_i\end{bmatrix}fi?=[1?qi?qi?1?pi?pi??]
可以繼續這么歸納下去,計算 Q(r∣l)Q(r\Big|l)Q(r∣∣∣?l) 等相關信息,無非就是一個連續區間的矩陣相乘后某個位置的結果。
∑i=kj+1i=kj+1?1P(Akj∣Xi=1)P(Xi=1∣Akj+1)P(Akj+1∣Akj)\sum_{i=k_j+1}^{i=k_{j+1}-1}\frac{P(A_{k_j}|X_i=1)P(X_i=1|A_{k_{j+1}})}{P(A_{k_{j+1}}|A_{k_j})}∑i=kj?+1i=kj+1??1?P(Akj+1??∣Akj??)P(Akj??∣Xi?=1)P(Xi?=1∣Akj+1??)?,用線段樹維護矩陣 fff。
分母就是 fff 矩陣從 kjk_{j}kj? 一直乘到 kj+1k_{j+1}kj+1?。
分子就是 fff 矩陣乘到 iii 位置時,只乘第二列(表示勝利),可以新定義一個矩陣 gig_igi?。
gi=[0qi0pi]g_{i}=\begin{bmatrix}0\quad\quad q_i\\0\quad\quad p_i\end{bmatrix}gi?=[0qi?0pi??],在乘到 iii 位置時變成乘 gig_igi?。
同樣用線段樹維護,gnow=flson?grson+glson?frson;fnow=flson?grsong_{now}=f_{lson}*g_{rson}+g_{lson}*f_{rson};f_{now}=f_{lson}*g_{rson}gnow?=flson??grson?+glson??frson?;fnow?=flson??grson?
最后就是具體實現問題了。
考慮插入兩個哨兵 0,n+10,n+10,n+1,初始局面答案就是一整個區間。
有涉及到詢問當前已知條件中的前驅 lll 后繼 rrr 問題,就需要用 STL 實現。
加點就用答案減去區間 (l,r)(l,r)(l,r) 的貢獻,再加上區間 (l,i)(l,i)(l,i) 和區間 (i,r)(i,r)(i,r) 的貢獻。
刪點就用答案減去區間 (l,i)(l,i)(l,i) 和區間 (i,r)(i,r)(i,r) 的貢獻,再加上區間 (l,r)(l,r)(l,r) 的貢獻。
code
#include <map> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct matrix {double c[2][2];// double * operator [] ( int x ) { return c[x]; }matrix() { memset( c, 0, sizeof( c ) ); }friend matrix operator + ( matrix u, matrix v ) {matrix ans;for( int i = 0;i < 2;i ++ )for( int j = 0;j < 2;j ++ )ans.c[i][j] = v.c[i][j] + u.c[i][j];return ans;}friend matrix operator * ( matrix u, matrix v ) {matrix ans;for( int i = 0;i < 2;i ++ )for( int j = 0;j < 2;j ++ )for( int k = 0;k < 2;k ++ )ans.c[i][j] += u.c[i][k] * v.c[k][j];return ans;}void print() {for( int i = 0; i < 2; i ++ ) {for( int j = 0; j < 2; j ++ )printf( "%.3f ", c[i][j] );printf( "\n" );}} }; #define maxn 200005 struct node { matrix f, g; }t[maxn << 2]; int n, m; char type; double ans; double p[maxn], q[maxn]; map < int, bool > x;#define lson now << 1 #define rson now << 1 | 1 #define mid ( ( l + r ) >> 1 )node operator + ( node x, node y ) {node ans;ans.f = x.f * y.f;ans.g = x.g * y.f + x.f * y.g;return ans; }void build( int now, int l, int r ) {if( l == r ) {t[now].f.c[0][0] = 1 - q[l];t[now].f.c[0][1] = t[now].g.c[0][1] = q[l];t[now].f.c[1][0] = 1 - p[l];t[now].f.c[1][1] = t[now].g.c[1][1] = p[l];// printf( "(%d):\n", l );// t[now].f.print();t[now].g.print();return;}build( lson, l, mid );build( rson, mid + 1, r );t[now] = t[lson] + t[rson];// printf( "{ %d } [%d, %d] ::\n", now, l, r );// t[now].f.print(); t[now].g.print(); }node query( int now, int l, int r, int L, int R ) {if( L <= l and r <= R ) return t[now];if( R <= mid ) return query( lson, l, mid, L, R );else if( mid < L ) return query( rson, mid + 1, r, L, R );else return query( lson, l, mid, L, R ) + query( rson, mid + 1, r, L, R ); }double Ask( int l, int r ) {node now = query( 1, 0, n + 1, l + 1, r );// now.f.print(); now.g.print();return now.g.c[x[l]][x[r]] / now.f.c[x[l]][x[r]]; }int main() {scanf( "%d %d %c %lf", &n, &m, &type, &p[1] );for( int i = 2;i <= n;i ++ ) scanf( "%lf %lf", &p[i], &q[i] );p[0] = q[0] = x[0] = 1, x[n + 1] = 0;build( 1, 0, n + 1 );ans = Ask( 0, n + 1 );// printf( "%f\n", ans );while( m -- ) {char opt[10]; int i, c;scanf( "%s", opt );if( opt[0] == 'a' ) {scanf( "%d %d", &i, &c );auto r = x.lower_bound( i );auto l = r;l --;x[i] = c;ans -= Ask( l -> first, r -> first );ans += Ask( l -> first, i );ans += Ask( i, r -> first );}else {scanf( "%d", &i );auto r = x.upper_bound( i );auto l = r;l --, l --;ans -= Ask( l -> first, i );ans -= Ask( i, r -> first );ans += Ask( l -> first, r -> first );x.erase( ++ l );}printf( "%f\n", ans );}return 0; }總結
以上是生活随笔為你收集整理的[UOJ299][CTSC2017] 游戏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓微店店长版不提示声音(安卓微店)
- 下一篇: 【学习笔记】平等博弈及常见的公平博弈类型