题解 P2911 【[USACO08OCT]牛骨头Bovine Bones】
写在最前:本人是刚入门的菜鸡,所掌握的概率知识也仅限于初中水平(不会期望),还请各位大佬多多喷我的垃圾题解 XD
题意简述
现有三个不同的骰子,面数分别为
数据范围:
思路讲解
看到这么小的数据范围,那当然是暴力枚举啦!况且这还是入门题,怎么可能如此难为我这种萌新呢。但是我的神仙同学说:
于是我把自己的头发都抓光了, 终于用
由于接下来的讲解可能略显冗长,这里先放一张我写的简化版的题解的图片(原是写给我的神仙同学看的),如果你看懂了那就可以不用看下面的讲解了。
好了,不管你是因为我写得过于晦涩、简略而没看懂,还是因为我的字写得太丑而不屑一看,抑或是好奇我的详细讲解有多啰嗦,你一定是准备开始看下文了。那么接下来正文就要开始了!
事实上第一眼看到这个题目,我立刻想到了自己小学时在某本数学趣味书上看到的一个喜欢赌博的数学家,他玩过这样一个游戏:掷两个骰子(正方体的那种),两个人分别对两个骰子的点数之和进行猜测,谁猜对了谁赢。而他发现:在这样的规则下,猜7胜率最高。于是他凭着这个发现赢了好多钱。但现在我觉得这个故事很可能是假的() 根据这个发现,很自然地,我们先研究两个骰子的情况。对于上述问题,我们可以列个表来解决:
| 1 | 2 | 3 | 4 | 5 | 6 | |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 6 | 7 | 8 | 9 | 10 | 11 | 12 |
可以观察到,7出现的次数最多。再想一想,就可以知道:当掷出两个相同的骰子时,若骰子有
接下来看一看当两个骰子面数不一样时会怎样(事实上大部分人应该已经能够得出亿些结论了,但我太菜了,只好继续研究)。仍然采用列表法,我们用面数分别为5和8的骰子试试看:
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
|---|---|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
根据这个表格,我们可以得出较为一般的结论了 (明明根据上个表格就行了) 。为了更清楚地说明,我给这张表格上了色:
好了!现在任何人都能毫无障碍地看出其中的规律,不用说大家应该也知道,但我还是啰嗦一下免得过不了审核:
若有两个骰子,它们的面数分别为
- 不同的点数之和的情况总数为
a+b-1 ,从小到大具体是2,3,4,...,a+b ; - 点数之和出现次数最多的是
1+a,1+a+1,1+a+2,...,1+b ,且总共有b-a+1 个出现次数最多的和; - 当和为
m 的出现次数不是最多时,设m 的出现次数为f(m) ,则
进行到这里,我们已经把两个骰子的问题研究得较为清楚了。事实上,最重要的结论是第二条,因为题目只要求我们求出和,而并不要求知道这个和出现的次数(或概率)。
接下来,我们加入第三个骰子。
如果现在在原来的表格的基础上直接加入一个骰子,那我们将会得到一个长方体,那样不太利于我们的思考(事实上这个长方体中数字的分布也有着和上文表格类似的规律,具体是怎样的请读者自行想象)。因此我们对这个表格再简化一下。由于我们只关心骰子的点数之和,并不关心这个和是如何得出的,我们可以将两个骰子构成的表格压缩成一条线段。根据上面的第一条结论,这条线段的长度应为 这个图大家应该想象得出来,我就不画了() 但这样的表示还是有很明显的缺陷,大家也一定能看出来,那就是这条线段上没有各个和出现次数的信息。没关系,我们可以把它变成一个柱状图:
这其实类似于频数分布直方图,但并不真的是。当我们做完这一步工作以后,再加入第三个骰子,事情将会变得容易许多。我们设这个骰子有
仍然要使用刚才的线段
当线段
当线段
当然这里
好啦,我们几乎大功告成啦!为什么是几乎呢,因为这里
点数之和出现次数最多的是
1+a,1+a+1,1+a+2,...,1+b ,且总共有b-a+1 个出现次数最多的和;
要使出现次数最多,那么
最后附上代码
#include<iostream>
#include<math.h>
using namespace std;
void swap(int &x,int &y)
//swap必须加上&取地址才能真正交换,类型必须写void
{ int t=x; x=y; y=t; }
int main()
{
int a,b,c;
cin>>a>>b>>c;
if(a<b) swap(a,b);
if(b<c) swap(b,c);
if(a<b) swap(a,b);
//冒泡排序
if(b<=a-c+1)
cout<<1+b+c;
else
cout<<2+a+(b-a+c-1)/2;//int除法自动下取整
return 0;
}
需要说明的是,这种方法也可以求出和的出现次数(概率),当然式子长得不太好看就是了,大家可以自己想一想哦!(明明想都不用想)
Update: 2020/8/6 修改了巨丑无比的代码
Update: 2020/11/29 代码和LaTeX有点小锅,修一修