1. 程式人生 > >NOIP2018模擬賽Potato 概率Dp 矩陣優化

NOIP2018模擬賽Potato 概率Dp 矩陣優化

NOIP2018模擬賽Potato

題目

在這裡插入圖片描述
在這裡插入圖片描述

分析

考慮動態規劃。
首先考慮到產生一個 j j 級土豆的條件是有兩個 j 1 j-1

級的土豆。
由於每次都把土豆往左移,所以每次都是後面空出來一塊盒子讓你放。
於是可以Dp,先求當前一共有 i i 個盒子,產生了一個 j j 級土豆的概率。(接下來都假設有 i
i
個盒子)
a [ i ] [ j ] =
a [ i 1 ] [ j 1 ] a [ i ] [ j 1 ] a[i][j]=a[i-1][j-1]\cdot a[i][j-1]

考慮產生一個 j j 級土豆,並且之後不再產生任何高於 j j 級土豆的概率。
A [ i ] [ j ] = a [ i ] [ j ] ( 1 a [ i 1 ] [ j ] ) A[i][j]=a[i][j]\cdot(1-a[i-1][j])
因為如果連一個 j j 級土豆都沒有產生的話,一定不會有更高階的土豆出現。
在此基礎上,求最終第 i i 個位置上是 j j 級土豆, [ i , i + n ] [i,i+n] 內的所有土豆等級和的期望。
f [ i ] [ j ] = j + E k = 1 j 1 ( f [ i + 1 ] [ k ] , A [ n i ] [ k ] ) f[i][j]=j+E_{k=1}^{j-1}(f[i+1][k], A[n - i][k])
其中 E E 表示的是加權平均,也就是
E ( x i , w i ) = x i w i w i E(x_i,w_i)=\frac{\sum x_i\cdot w_i}{\sum w_i}
也就是考慮 i + 1 i+1 個位置上最終為 k k 級別的土豆的期望:先產生一個 k k 級別的土豆,之後都不在產生 k k 級別的土豆,在此基礎上乘上這個情況下之後所有土豆等級和的期望。
但是要特殊考慮一種情況,就是 j = 1 j=1 ,這種情況下 i + 1 i+1 位置只能直接產生一個 2 2 級的土豆。
所以額外新建狀態, b [ i ] [ j ] b[i][j] 表示最開始放了一個 2 2 級的土豆,合成了 j j 的土豆的概率, B [ i ] [ j ] B[i][j] 表示之後都不再產生高於 j j 級別的土豆。轉移方程:
b [ i ] [ j ] = b [ i ] [ j 1 ] ( 1 a [ i 1 ] [ j 1 ] ) b[i][j]=b[i][j-1]\cdot(1-a[i-1][j-1])
B [ i ] [ j ] = b [ i ] [ j ] ( 1 a [ i 1 ] [ j ] ) B[i][j]=b[i][j]\cdot (1-a[i-1][j])
f [ i ] [ 1 ] = E k = 2 i n f ( f [ i + 1 ] [ k ] , B [ n i ] [ k ] ) f[i][1]=E_{k=2}^{inf}(f[i+1][k],B[n-i][k])
最終的答案是 A n s = k = 1 i n f ( f [ 1 ] [ k ] A [ n ] [ k ] ) Ans=\sum_{k=1}^{inf}(f[1][k]\cdot A[n][k])
轉移的複雜度是 O ( n 3 ) O(n^3) 的,只能通過 S u b t a s k 4 Subtask4
然而不難發現,土豆等級越高產生的概率應該是指數級別下降的。所以考慮捨去大於某個等級的土豆(標解捨去的是50級以上的土豆)
這樣的話,當 n 50 n\ge 50 的時候 i + 1 > i i+1->i 的轉移方程是一模一樣的,採用矩陣優化即可。
複雜度 O ( 5 0 3 l o g n ) O(50^3logn)

程式碼

#include<bits/stdc++.h>
int ri() {
	char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
	for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
double a[52][52], b[52][52], s[52][52], f[52][52];
struct Maxtir {
	double m[52][52];
	Maxtir() {memset(m, 0, sizeof(m));}
	double *operator[](int i) {return m[i];}
	Maxtir operator * (Maxtir b) {
		Maxtir c;
		for(int i = 1;i <= 51; +