题目描述
题目大意:两个人A、B,血量分别为HA、HB,轮流掷骰子,每个人掷骰子的6种情况都有一定的概率,谁点数小谁扣一滴血,没血了就输了,问A赢的概率。
坑点:血量输入是反的,而且听说总概率还可能不等于1。-_-||
题解
dp[i][j]表示A有i血,B有j血A赢的概率。概率正推,dp[x][0]=1.0(x!=0),然后dp[i][j]=dp[i][j-1]*p1+dp[i-1][j]*p2,其中p1为每次A赢的概率,p2位每次B赢的概率。
注意平局不贡献答案,我们要预先处理出正确的p1和p2,忽略平局的影响。(说个类比,就是生物上的某基因型致死然后问你某个生物是某个基因型的概率)
然后由于double有爆空间的风险,直接滚动第一维即可。但是我想到一个问题,这样赋初值时让dp[0][0]=dp[1][0]=1.0,当i和j都为0时的状态的值不就错了吗?但是我们枚举状态时根本不会去算i=0或j=0的情况,所以根本没有这个转移,总之zenzen没问题。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
int n,m;
double dp[2][2002],a[7],b[7];
int main(){
while(~ scanf("%d%d",&m,&n)){
for(int i = 1; i <= 6; i++) scanf("%lf",&a[i]);
for(int i = 1; i <= 6; i++) scanf("%lf",&b[i]);
double p1 = 0.0,p2 = 0.0,sum;
for(int i = 0; i <= m; i++)
dp[0][i] = dp[1][i] = 0.0;
for(int i = 1; i <= 6; i++)
for(int j = 1; j <= 6; j++){
if(i > j) p1 += a[i] * b[j];
if(i < j) p2 += a[i] * b[j];
}
sum = p1 + p2;
p1 /= sum;
p2 /= sum;
int x = 0;
dp[0][0] = dp[1][0] = 1.0;
for(int i = 1; i <= n; i++){
x ^= 1;
for(int j = 1; j <= m; j++)
dp[x][j] = dp[x][j-1] * p1 + dp[x^1][j] * p2;
}
printf("%.6lf\n",dp[x][m]);
}
return 0;
}