题目传送门OvO
题目描述
贝西喜欢玩桌上扮演游戏(BRPG),所以她说服农场主约翰开车送她到商店,在那里她买了三个骰子。
这三个骰子分别有S1、S2和S3个面。每个有S面的骰子每一面的点数分别是1,2,3……,S-1,S.
贝西每次同时扔出三个骰子,她一直扔呀扔,试图找出三个骰子点数之和哪个出现的次数最多。
现在给定三个骰子中每个骰子的面数,求三个骰子的点数和哪个最频繁出现。如果有多解,输出最小的一个。
输入输出格式
输入格式
S1 +<空格>+ S2 +<空格>+ S3
输出格式
最小解
这题很简单啊。看了网上很多大佬的做法,再看看我的暴力,,,
其实这道题我就是一个循环然后找找找找的过程。
题意大概就是某个熊孩子在玩三个多面体骰子,要我们找出三个骰子不同面相加之后和出现最频繁的那一个。
我的思路其实就是强行搜。定义3个数组代表骰子S个面上的数,再定义一个数组盛放这3个骰子各个面上的和就OK了。
考虑到会不会TLE,直接用和代表下标。
那么,上代码:
#include<bits/stdc++.h>
using namespace std;
int a[100000+5],b[100000+5],c[100000+5],d[2000000+5],ans,asf;//四个数组以及用来输出的answer
int main(){
int a1,b1,c1;//定义输入的3个骰子的面数
cin>>a1>>b1>>c1;//输入
for(int i=1;i<=a1;i++){
a[i]=i;
}
for(int i=1;i<=b1;i++){
b[i]=i;
}
for(int i=1;i<=c1;i++){
c[i]=i;
}//将3个数组里都装上骰子的各个面上的数,由于是1,2,3...数列,所以可以直接用i表示。
for(int i=1;i<=a1;i++){
for(int j=1;j<=b1;j++){
for(int k=1;k<=c1;k++){
int qwe;
qwe=a[i]+b[j]+c[k];
d[qwe]++;//将3个面上的和都扔进第四个数组里去...
}
}
}
for(int i=1;i<=200000+5;i++){
if(d[i]>ans){
ans=d[i];//判断是不是最大的,由于是如果相等就输出最小所以在判断时是没有=的。
asf=i;//其实这个才是用来输出的】
}
}
cout<<asf;
return 0;
}
接下来给大家转一下一位大佬的题解:
突然有大胆的想法能不能O(1)过,利用了期望,一开始想得挺简单没想到推广后是个复杂的分布问题,还得多谢Manchery同学。
考虑每个骰子的期望,三个骰子a,b,c。以a为例,可得骰子的期望为:
1/a×1+1/a×2+1/a×3……+1/a×a = (a+1)/2
3个骰子期望相加化简后就是这样
(a+b+c+3)/2
当然最后算出来可能是个小数喽
因为要最小的,所以直接取整就是答案(当然这想法是有漏洞的)
先举个栗子,比如3 2 3,代入后得到5.5,可知5和6应该是同个概率,于是取小点的5。
兴高采烈一发W了两个点(不愧是入门难度数据这都能有80)
问题就在于,某些期望可能会均匀地分布在一个较大的区间内,比如2 3 7这类数据,我列出所有情况
3 4 5 6 7 8 9
4 5 6 7 8 9 10
5 6 7 8 9 10 11
4 5 6 7 8 9 10
5 6 7 8 9 10 11
6 7 8 9 10 11 12
可以看出是答案是6,那原来的公式出了啥问题
计算得到期望是7.5,然而,6到9都是最高频率,而我们得到的是最中间的值,可这区间多大却没有考虑到,,,
好在3个数,可以总结规律
if(s3>s1+s2) ans = s1+s2+1
if(s2>s1+s3) ans = s1+s3+1
if(s1>s3+s2) ans = s2+s3+1
else 直接算期望
主要代码:
int s1, s2, s3, ost;
int main(){
scanf("%d%d%d", &s1, &s2, &s3);
if(s3>s1+s2)printf("%d", s1+s2+1);
else if(s2>s1+s3)printf("%d", s1+s3+1);
else if(s1>s3+s2)printf("%d", s3+s2+1);
else printf("%d", (s1+s2+s3+3)/2);
return 0;
}