洛谷[P2911]牛骨头

题目传送门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;
}
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值