题解:P2911 [USACO08OCT] Bovine Bones G

· · 题解

更好的阅读体验。

题解区的思路大都是暴力枚举,看完后我突然想起来有一个 O(1) 的做法。

我有一计!

题目分析

找出三个骰子所有可能的和中出现次数最高的那个,如果有多个和出现次数相同,则输出字典序最小的那个。

解决思路

我们可以通过分析骰子面数之间的关系,直接计算最可能出现的和,而不需要枚举所有可能的组合。

三个骰子的和最可能出现在中间区域,具体位置取决于三个骰子面数的相对大小。

数学原理

本题解的知识点牵扯到概率论,读者自重。

这玩意基于概率分布的性质:

\left\lfloor\frac{b+c-a-1}{2}\right\rfloor+2+a

读者若想了解,可以在 OI Wiki 上搜索,这包含了概率论与组合数学离散差分

简短证明

核心思路

三个独立均匀分布随机变量之和的众数出现在分布的中心区域,具体位置取决于三个面数的相对大小。

情况分析

情况1:最大骰子足够大 (Z+Y\le X+1)

情况2:三个骰子面数相近 (Z+Y>X+1)

代码实现

这里提供两种做法。

```cpp #include <bits/stdc++.h> using namespace std; int a,b,c; int main(){ cin>>a>>b>>c; //排序使 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; } return 0; } ``` $O(n^3)$ 做法(即暴力,不解释): ```cpp #include <bits/stdc++.h> using namespace std; int freq[110],ans,cnt,s1,s2,s3;//统计和出现的频率。 int main(){ cin>>s1>>s2>>s3; //枚举所有可能的骰子组。 for(int i=1;i<=s1;i++){ for(int j=1;j<=s2;j++){ for(int k=1;k<=s3;k++){ int sum=i+j+k; freq[sum]++; } } } //找出出现频率最高的最小和。 for(int sum=3;sum<=s1+s2+s3;sum++){ if(freq[sum]>cnt){ cnt=freq[sum]; ans=sum; } } cout<<ans; return 0; } ``` **update**:2025.7.22 修正了两处小错误。 **update**:2025.9.19 更加详细地修改了一下保证更好的阅读体验。