链接
背景
(USACO) (2008) (Oct) (Gold) (T1) , (Luogu) (P2911/BZOJ1599)
题意
给定三个骰子,分别有 (s1,s2,s3) 个面(每个骰子从 (1) 开始标号每个面)。求出现次数最多的三骰子数字和。有多个数字和出现次数均为最多时,只要求最小的数字和。
解法
从朴素解法开始:由于 (s1 leqslant 20,s2 leqslant 20,s3 leqslant 40) ,故不难想到 (O(s1s2s3)) 枚举出所有的情况,开个桶记下所有三骰子数字和的出现次数,找出最大的桶所在的位置即可。
另一种解法
是否有一个数学方法可以 (O(1)) 计算答案呢?显然是有的。
不妨手绘出出现次数的分布图像(如下图),

发现最值点在相当长的一段区间内分布。假设 (s1 leqslant s2 leqslant s3) ,则通过观察或打表容易发现在 (s1+s2<s3) 时,最值点区间的左端点(即本题答案)为 (s1+s2+1) ;否则答案为 (frac{s1+s2+s3+3}{2}) (根据每个点数的期望计算)。
代码
$View$ $Code$
```cpp
#include
using namespace std;
inline int read()
{
int ret=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
ret=(ret<<1)+(ret<<3)+ch-'0';
ch=getchar();
}
return ret*f;
}
int s1,s2,s3,cnt[85],ans,maxn;
int main()
{
s1=read();
s2=read();
s3=read();
for(register int i=1;i<=s1;i++)
for(register int j=1;j<=s2;j++)
for(register int k=1;k<=s3;k++)
cnt[i+j+k]++;
for(register int i=1;i<=s1+s2+s3;i++)
{
if(maxn
另一份代码
$View$ $Code$
```cpp
#include
using namespace std;
inline int read()
{
int ret=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
ret=(ret<<1)+(ret<<3)+ch-'0';
ch=getchar();
}
return ret*f;
}
int s1,s2,s3,cnt[85],ans,maxn;
int main()
{
s1=read();
s2=read();
s3=read();
if(s1+s2