1. 程式人生 > >【bzoj4832】[Lydsy2017年4月月賽]抵制克蘇恩 概率期望dp

【bzoj4832】[Lydsy2017年4月月賽]抵制克蘇恩 概率期望dp

概率dp 題解 pri 了無 cpp 。。 時間復雜度 ros 多少

題目描述

你分別有a、b、c個血量為1、2、3的奴隸主,假設英雄血量無限,問:如果對面下出一個K點攻擊力的克蘇恩,你的英雄期望會受到到多少傷害。

輸入

輸入包含多局遊戲。 第一行包含一個整數 T (T<100) ,表示遊戲的局數。 每局遊戲僅占一行,包含四個非負整數 K, A, B 和 C ,表示克蘇恩的攻擊力是 K ,你有 A 個 1 點血量的奴隸 主, B 個 2 點血量的奴隸主, C 個 3 點血量的奴隸主。 保證 K 是小於 50 的正數, A+B+C 不超過 7 。

輸出

對於每局遊戲,輸出一個數字表示總傷害的期望值,保留兩位小數。

樣例輸入

1
1 1 1 1

樣例輸出

0.25


題解

概率期望dp

一開始直接上了復雜度多了K的概率dp然後T死了。。。

由於期望具有可加性,因此不需要維護受到傷害為某值的各種情況,而是維護其期望值。

設$f[i][j][k][l]$表示前$i$次攻擊,分別剩下$j$、$k$、$l$個血量為1、2、3的奴隸主時受到傷害的期望。那麽直接考慮這次攻擊的情況直接轉移即可。

註意此時我們設的是總情況下的期望,因此在英雄受到傷害時期望值的增加應該為 概率*取值 ,取值為1,因此需要加上概率。所以再維護一個某情況的概率值即可。

時間復雜度$O(TK·8^3)$

註意千萬不要把代碼碼錯!(轉移那裏碼錯WA了無數次QAQ)

#include <cstdio>
#include <cstring>
double p[55][8][8][8] , f[55][8][8][8];
int main()
{
	int T;
	scanf("%d" , &T);
	while(T -- )
	{
		memset(p , 0 , sizeof(p)) , memset(f , 0 , sizeof(f));
		int n , a , b , c , i , j , k , l;
		double ans = 0;
		scanf("%d%d%d%d" , &n , &a , &b , &c) , p[0][a][b][c] = 1;
		for(i = 0 ; i < n ; i ++ )
		{
			for(j = 0 ; j <= 7 ; j ++ )
			{
				for(k = 0 ; k <= 7 ; k ++ )
				{
					for(l = 0 ; l <= 7 ; l ++ )
					{
						p[i + 1][j][k][l] += p[i][j][k][l] / (1 + j + k + l) , f[i + 1][j][k][l] += (f[i][j][k][l] + p[i][j][k][l]) / (1 + j + k + l);
						if(j) p[i + 1][j - 1][k][l] += p[i][j][k][l] * j / (1 + j + k + l) , f[i + 1][j - 1][k][l] += f[i][j][k][l] * j / (1 + j + k + l);
						if(k)
						{
							if(j + k + l == 7) p[i + 1][j + 1][k - 1][l] += p[i][j][k][l] * k / (1 + j + k + l) , f[i + 1][j + 1][k - 1][l] += f[i][j][k][l] * k / (1 + j + k + l);
							else p[i + 1][j + 1][k - 1][l + 1] += p[i][j][k][l] * k / (1 + j + k + l) , f[i + 1][j + 1][k - 1][l + 1] += f[i][j][k][l] * k / (1 + j + k + l);
						}
						if(l)
						{
							if(j + k + l == 7) p[i + 1][j][k + 1][l - 1] += p[i][j][k][l] * l / (1 + j + k + l) , f[i + 1][j][k + 1][l - 1] += f[i][j][k][l] * l / (1 + j + k + l);
							else p[i + 1][j][k + 1][l] += p[i][j][k][l] * l / (1 + j + k + l) , f[i + 1][j][k + 1][l] += f[i][j][k][l] * l / (1 + j + k + l);
						}
					}
				}
			}
		}
		for(i = 0 ; i <= 7 ; i ++ )
			for(j = 0 ; j <= 7 ; j ++ )
				for(k = 0 ; k <= 7 ; k ++ )
					ans += f[n][i][j][k];
		printf("%.2lf\n" , ans);
	}
	return 0;
}

【bzoj4832】[Lydsy2017年4月月賽]抵制克蘇恩 概率期望dp