Luogu T103187 东方CannonBall 概率dp

题目背景

东方CannonBall(译名东方大炮弹)是近期发布的第一款获得ZUN授权的商业东方二次创作手机游戏,游戏关卡中玩家在类似大富翁的棋盘上与CPU或是玩家进行对战。

题目描述

在游戏中,每位玩家拥有若干个六面骰子。当两名玩家相遇时,将会通过掷出所有骰子的方式判定胜负。你拥有xx个骰子,而你的对手拥有yy个骰子,请问你胜率,即你的点数和大于对手的概率是多少?

正式地说,将玩家的nn个骰子编号为1..n1..n,在每次掷骰子时,第ii个骰子的点数a_iai?会在\{1,2,3,4,5,6\}{1,2,3,4,5,6}中等概率随机选取,玩家的点数和C_n=\sum_{1\le i \le n} a_iCn?=∑1≤i≤n?ai?,求P(C_x>C_y)P(Cx?>Cy?)

输入格式

一行2个整数,依次表示你的骰子数xx和对手的骰子数yy。

输出格式

一行一个百分数,四舍五入保留小数点后2位小数,表示你的胜率。

输入输出样例

输入 #1复制

1 1

输出 #1复制

41.67%

输入 #2复制

500 499

输出 #2复制

52.22%

说明/提示

对于样例1,双方有\frac {1} {6}61?的概率掷出相同值,其他情况下输赢各占一半,故答案为\frac {5} {12}125?

本题使用文本方式比较

数据规模

对于 30\%30% 的数据,保证 x+y \le 8x+y≤8。

对于 60\%60% 的数据,保证 x,y \le 10x,y≤10

对于 100\%100% 的数据,保证 1 \le x, y\leq 10001≤x,y≤1000

做法如题。100分目测需要加高精度(+ × / 运算)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5
 6 using namespace std;
 7 typedef long long ll;
 8
 9 ll read(){
10     ll a = 0; char l = ‘ ‘,c = getchar();
11     while(c < ‘0‘||c > ‘9‘)l = c,c = getchar();
12     while(‘0‘ <= c&&c <= ‘9‘)a = a*10+c-‘0‘,c = getchar();
13     if(l == ‘-‘)return -a; return a;
14 }
15
16 ll f[2][2][6010],s[2][6010];
17 ll x,y,win,tot;
18
19 int main(){
20     x = read(),y = read();
21 //    for(int i = 1;i <= 6;i++)f[0][0][i] = f[0][1][i] = 1;
22     f[0][0][0] = f[0][1][0] = 1;
23     for(int i = 1;i <= x;i++){
24         memset(f[i&1][0],0,sizeof(f[i&1][0]));
25         for(int j = x*6;j >= 0;j--)if(f[~i&1][0][j])
26             for(int k = 1;k <= 6;k++)
27                 f[i&1][0][j+k] += f[~i&1][0][j];
28     }
29     for(int i = 1;i <= y;i++){
30         memset(f[i&1][1],0,sizeof(f[i&1][1]));
31         for(int j = y*6;j >= 0;j--)if(f[~i&1][1][j]){
32 //            printf("%d ",f[~i&1][1][j]);
33             for(int k = 1;k <= 6;k++)
34                 f[i&1][1][j+k] += f[~i&1][1][j];
35         }//putchar(‘\n‘);
36     }
37 //    for(int i = 1;i <= x*6;i++)
38 //        s[0][i] = s[0][i-1]+f[0][i];
39 //    for(int i = 1;i <= y*6;i++)
40 //        s[1][i] = s[1][i-1]+f[y&1][1][i];
41     for(int i = x;i <= x*6;i++){
42         ll cur = 0;
43         for(int j = y;j < i;j++)cur += f[x&1][0][i]*f[y&1][1][j];
44         win += cur;
45         for(int j = i;j <= y*6;j++)cur += f[x&1][0][i]*f[y&1][1][j];
46         tot += cur;
47     }
48
49 //    cout << win << ‘ ‘ << tot << endl;
50 //    for(int i = 0;i <= x*6;i++)printf("%d ",f[x&1][0][i]);putchar(‘\n‘);
51 //    for(int i = 0;i <= y*6;i++)printf("%d ",f[y&1][1][i]);putchar(‘\n‘);
52
53     double ans = 1.0*win/tot*100;
54     printf("%.2f%%",ans);
55 return 0;
56 }

60分代码

原文地址:https://www.cnblogs.com/Wangsheng5/p/11666536.html

时间: 2024-10-07 13:56:39

Luogu T103187 东方CannonBall 概率dp的相关文章

Codeforces 28C [概率DP]

/* 大连热身D题 题意: 有n个人,m个浴室每个浴室有ai个喷头,每个人等概率得选择一个浴室. 每个浴室的人都在喷头前边排队,而且每个浴室内保证大家都尽可能均匀得在喷头后边排队. 求所有浴室中最长队伍的期望. 思路: 概率dp dp[i][j][k]代表前i个浴室有j个人最长队伍是k的概率. 枚举第i个浴室的人数.然后转移的时候其实是一个二项分布. */ #include<bits/stdc++.h> using namespace std; int jilu[55]; double dp[

hdu 3076 ssworld VS DDD (概率dp)

///题意: /// A,B掷骰子,对于每一次点数大者胜,平为和,A先胜了m次A赢,B先胜了n次B赢. ///p1表示a赢,p2表示b赢,p=1-p1-p2表示平局 ///a赢得概率 比一次p1 两次p0*p1 三次 p0^2*p1,即A赢的概率为p1+p*p1+p^2*p1+...p^n*p1,n->无穷 ///即a_win=p1/(1-p);b_win=p2/(1-p); ///dp[i][j]表示a赢了j次,b赢了i次的概率 ///dp[i][j]=dp[i-1][j]*b_win+dp[

hdu 3853 概率DP 简单

http://acm.hdu.edu.cn/showproblem.php?pid=3853 题意:有R*C个格子,一个家伙要从(0,0)走到(R-1,C-1) 每次只有三次方向,分别是不动,向下,向右,告诉你这三个方向的概率,以及每走一步需要耗费两个能量,问你走到终点所需要耗费能量的数学期望: 回头再推次,思想跟以前的做过的类似 注意点:分母为0的处理 #include <cstdio> #include <cstring> #include <algorithm>

hdu4089(公式推导)概率dp

题意:有n人都是仙剑5的fans,现在要在官网上激活游戏,n个人排成一个队列(其中主角Tomato最初排名为m), 对于队列中的第一个人,在激活的时候有以下五种情况: 1.激活失败:留在队列中继续等待下一次激活(概率p1) 2.失去连接:激活失败,并且出队列然后排到队列的尾部(概率p2) 3.激活成功:出队列(概率p3) 4.服务器瘫:服务器停止服务了,所有人都无法激活了(概率p4) 求服务器瘫痪并且此时Tomato的排名<=k的概率. 解法:ans[i][j]表示i个人出于第j个位置要到目的状

poj3071(概率DP)

题意:淘汰赛制,2^n(n<=7)个队员.给出相互PK的输赢概率矩阵.问谁最有可能赢到最后. 解法:ans[i][j]表示第i个队员第j轮胜出的概率.赢到最后需要进行n场比赛.算出每个人赢到最后的ans[i][n].写出序号的二进制发现一个规律,两个队员i.j如果碰到,那么一定是在第get(i,j)场比赛碰到的.get(i,j)计算的是i和j二进制不同的最高位,这个规律也比较明显. 代码: /****************************************************

【Foreign】开锁 [概率DP]

开锁 Time Limit: 10 Sec  Memory Limit: 256 MB Description Input Output Sample Input 4 5 1 2 5 4 3 1 5 2 2 5 4 3 1 5 3 2 5 4 3 1 5 4 2 5 4 3 1 Sample Output 0.000000000 0.600000000 0.900000000 1.000000000 HINT Main idea 一个宝箱内有一个可以开启别的宝箱的钥匙,可以选择k个宝箱,询问能开

POJ 2151 Check the difficulty of problems (概率DP)

题意:ACM比赛中,共M道题,T个队,pij表示第i队解出第j题的概率 ,求每队至少解出一题且冠军队至少解出N道题的概率. 析:概率DP,dp[i][j][k] 表示第 i 个队伍,前 j 个题,解出 k 个题的概率,sum[i][j] 表示第 i 个队伍,做出 1-j 个题的概率,ans1等于, T个队伍,至少解出一个题的概率,ans2 表示T个队伍,至少解出一个题,但不超过N-1个题的概率,最后用ans1-ans2即可. 代码如下: #pragma comment(linker, "/STA

UVALive 6672 Bonus Cards 概率dp

题意呢 就是有两种售票方式 一种是icpc 一种是其他方式 icpc抢票成功的概率是其他方式的2倍…… 这时 一个人出现了 他通过内幕知道了两种抢票方式各有多少人 他想知道自己如果用icpc抢票成功的概率是多少 用acm抢票成功的概率是多少…… 做过不多的概率dp 还在摸索…… dp[i][j]代表第i轮有j个icpc的人已经有票了…… 当然同时i-j个通过其他方式抢票的人也有票了 这就是用同样的函数搜两次的原理…… 优化一次i<=a 一次是把初始化放到for里…… 第一次见这么卡时间的题……

HDU 4599 Dice (概率DP+数学+快速幂)

题意:给定三个表达式,问你求出最小的m1,m2,满足G(m1) >= F(n), G(m2) >= G(n). 析:这个题是一个概率DP,但是并没有那么简单,运算过程很麻烦. 先分析F(n),这个用DP来推公式,d[i],表示抛 i 次连续的点数还要抛多少次才能完成.那么状态转移方程就是 d[i] = 1/6*(1+d[i+1]) + 5/6*(1+d[1]), 意思就是说在第 i 次抛和上次相同的概率是1/6,然后加上上次抛的和这一次,再加上和上次不同的,并且又得从第1次开始计算. 边界就是