NOIP2018模拟赛Potato 概率Dp 矩阵优化

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lvzelong2014/article/details/83501817

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; ++i)
			for(int j = 1;j <= 51; ++j)
				for(int k = 1;k <= 51; ++k)
					c[i][j] += m[i][k] * b[k][j];
		return c;
	}
}A, B;
void Pow(int k) {B = A; for(;k; A = A * A, k >>= 1) if(k & 1) B = B * A;}
int main() {
	freopen("potato.in","r",stdin);
	freopen("potato.out","w",stdout);
	int n = ri(); double r = 0, p1 = ri() / 1e9, p2 = 1 - p1;
	for(int i = 1;i <= 50; ++i)
		for(int j = 1;j <= 50; ++j) {
			if(j == 1) a[i][j] += p1;
			if(j == 2) a[i][j] += p2, b[i][j] += p2;
			a[i][j] += a[i][j - 1] * a[i - 1][j - 1];
			b[i][j] += b[i][j - 1] * a[i - 1][j - 1];
		}
	for(int i = 50; i; --i)
		for(int j = 1;j <= 50; ++j)
			a[i][j] *= (1 - a[i - 1][j]), b[i][j] *= (1 - a[i - 1][j]);
	for(int i = 1;i <= 50; ++i) f[50][i] = i;
	for(int i = 49; ~i; --i) {
		for(int k = 2;k <= 50; ++k) 
			f[i][1] += f[i + 1][k] * b[50 - i][k], s[i][1] += b[50 - i][k];
		for(int j = 2;j <= 50; ++j) 
			for(int k = 1;k < j; ++k)
				f[i][j] += f[i + 1][k] * a[50 - i][k], s[i][j] += a[50 - i][k];
		for(int j = 1;j <= 50; ++j) 
			(f[i][j] /= s[i][j]) += j;
	}
	if(n <= 51) {
		for(int i = 1;i <= 50; ++i) 
			r += a[n][i] * f[51 - n][i];
		return printf("%.10lf\n", r), 0;
	}
	A[1][51] = A[51][51] = 1;
	for(int k = 2;k <= 50; ++k) A[1][k] += b[50][k] / s[0][1];
	for(int j = 2;j <= 50; A[j][51] = j, ++j) 
		for(int k = 1;k < j; ++k) 
			A[j][k] += a[50][k] / s[0][j];
	Pow(n - 52);
	for(int i = 1;i <= 50; ++i) {
		double s = 0;
		for(int j = 1;j <= 50; ++j)
			s += B[i][j] * f[0][j];
		s += B[i][51];
		r += s * a[50][i];
	}
	printf("%.10lf\n", r);
	return 0;
}


猜你喜欢

转载自blog.csdn.net/lvzelong2014/article/details/83501817
今日推荐