牛牛与牛妹的游戏

链接:https://ac.nowcoder.com/acm/problem/21626 题目: 牛牛 和 牛妹 正在玩一个游戏
牛牛扔了a个b面的骰子
牛妹扔了c个d面的骰子
对于一个x面的骰子,每个面依次会写有1到x的数
一个玩家的得分就是每个骰子朝上的面的数字的总和,一个玩家能赢另一个玩家当且仅当得分严格大于另一个玩家,给你a,b,c,d,如果牛牛不可能赢,输出-1
【牛牛与牛妹的游戏】否则假设你知道了牛牛赢了,但是不知道牛牛和牛妹的具体分数,返回牛牛的期望得分
输入一行,包含4个整数a,b,c,d (1 ≤ a,b,c,d ≤ 50) 输出一个浮点数,误差在1e-3以内

输入 1 2 1 5 输出 2.0示例 2 输入 3 1 1 3 输出 3.0示例3 输入 1 5 1 1 输出 3.4999999999999996示例4 输入 2 6 50 30 输出 -1.0示例5 输入 50 11 50 50 输出 369.8865999182022

思路:题目意思是牛牛能赢的情况下的得分期望,所以我们只需要算出牛牛能赢的所有情况的总数,再算出牛牛能赢的每一种情况下牛牛能得的分,计算其总和,两者相除即可;dp[i][j]表示掷了i个骰子,得分为j的情况的有多少种. 递推方程:
dp[i][j]+=dp[i-1][j-k] (j>=k,k代表第i个骰子的点数)

代码:
//牛牛与牛妹的游戏#include #include #include #include using namespace std; typedef long long ll; const int maxn=55; double dp1[maxn][2600], dp2[maxn][2600]; double add[2600]; //add[j]牛妹的得分小于等于j的情况有多少种 int main() { int a,b,c,d; double ans=0; scanf("%d%d%d%d", &a, &b, &c, &d); // memset(dp,0,sizeof(dp)); dp1[0][0]=1; dp2[0][0]=1; if(a*b<=c) printf("-1.0\n"); else { for(int i=1; i<=a; i++) { for(int j=i; j<=b*i; j++) { for(int k=1; k<=b; k++) { if(j>=k) dp1[i][j]+=dp1[i-1][j-k]; //牛牛第i回合得j分的可能情况数 } } }for(int i=1; i<=c; i++) { for(int j=i; j<=d*i; j++) { for(int k=1; k<=d; k++) { if(j>=k) dp2[i][j]+=dp2[i-1][j-k]; //牛妹第i回合得j分的可能情况数 } } } for(int i=c; i<=c*d; i++) { add[i]+=add[i-1]+dp2[c][i]; } double result1, result2=0; for(int i=c+1; i<=a*b; i++) { result2+=dp1[a][i]*(add[i-1] ? add[i-1] : add[c*d]); //计算分母 } for(int i=c; i<=c*d; i++) { for(int j=i+1; j<=a*b; j++) { result1+=dp1[a][j]*j*dp2[c][i]; //分子 } } printf("%lf\n", result1/result2); } return 0; }

    推荐阅读