小天的 Minecraft(牛客)

写在前面:

牛客每日一题持续更新中!

今天给彦祖和亦菲们带来的是 小天的 Minecraft

题目如下:

1. 题目描述

在游戏里,破坏沙砾会掉落物品,概率分布如下:

  • 铜粒:概率 \frac{a}{16}

  • 银粒:概率 \frac{b}{16}

  • 金粒:概率 \frac{c}{16}

  • 其它:概率 \frac{16-a-b-c}{16}

制作铜镐需要:

  • 4 个铜粒 → 1 个铜锭

  • 3 个铜锭 → 1 个铜镐

  • 铜镐只能在 铜工作台 或 银工作台 或 金工作台 上制作

  • 铜工作台:1 个铜锭(4 铜粒)

  • 银工作台:1 个银锭(4 银粒)

  • 金工作台:1 个金锭(4 金粒)

能做出铜镐的条件是以下之一:

  1. 铜工作台路线:X≥16(12 铜粒做镐 + 4 铜粒做铜工作台)

  2. 银工作台路线:X≥12 且 Y≥4

  3. 金工作台路线:X≥12 且 Z≥4

注意:路线 2 和路线 3 可能有重叠(如果 X≥12,Y≥4,Z≥4 则同时满足两个路线),但概率计算时要用容斥原理。


2. 算法描述

设:

  • A:铜工作台路线事件

  • B:银工作台路线事件

  • C:金工作台路线事件

则:

        P(A)=P(X≥16))                                                                                                      P(B)=P(X≥12,Y≥4)                                                                                                  P(C)=P(X≥12,Z≥4)                                                                                P(B∩C)=P(X≥12,Y≥4,Z≥4)

最终概率:

P=P(A)+P(B)+P(C)−P(B∩C)

因为 A与 B,C 互斥(若 X≥16 则 Y=Z=0,不满足 Y≥4 或 Z≥4)。


3. 计算实现

直接枚举所有可能的 (x,y,z) 满足:

  • x+y+z≤16

  • 且满足上述任一条件

计算多项概率并累加。

已知铜镐需要12个铜粒,而工作台需要4个相同的金属粒

所以 两种情况

第一种是人品爆炸,16个全是铜粒,概率为pow(a/16.0,16)

第二种是拿到12个铜粒,剩下四个银粒或者金粒,

概率为pow(a/16.0,12)*(pow(b/16.0)+pow(c/16.0,4))*_{16}^{4}\textrm{C}

4.代码实现

C/C++版本:

#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;

int main() {
    int t;  // 测试数据组数
    cin >> t;
    
    // 计算分母:16的16次方,因为每个沙砾有16种可能结果,共16个沙砾
    const double denominator = pow(16, 16);
    
    for (int i = 0; i < t; i++) {
        int a, b, c;  // 铜粒、银粒、金粒的概率分子(分母固定为16)
        cin >> a >> b >> c;
        
        // 计算分子:
        // 1. pow(a, 16): 16个沙砾全部掉落铜粒的概率(可以直接制作铜工作台+铜镐)
        // 2. 1820 * pow(a, 12) * (pow(b, 4) + pow(c, 4)): 
        //    - 1820是组合数C(16,4),表示从16个位置中选4个放银粒或金粒
        //    - pow(a, 12): 12个铜粒的概率
        //    - pow(b, 4): 4个银粒的概率(制作银工作台)
        //    - pow(c, 4): 4个金粒的概率(制作金工作台)
        double numerator = pow(a, 16) + 1820 * pow(a, 12) * (pow(b, 4) + pow(c, 4));
        
        // 计算总概率:分子/分母
        double P = numerator / denominator;
        
        // 输出结果,保留10位小数
        cout << fixed << setprecision(10) << P << endl;
    }
    return 0;
}

Python版本:

import math

def main():
    t = int(input().strip())  # 测试数据组数
    
    # 计算分母:16的16次方
    denominator = 16 ** 16
    
    for _ in range(t):
        a, b, c = map(int, input().split())
        
        # 计算分子:
        # 1. a**16: 16个沙砾全部掉落铜粒
        # 2. 1820 * a**12 * (b**4 + c**4): 
        #    - 1820是组合数C(16,4)
        #    - 12个铜粒 + 4个银粒或金粒
        numerator = a ** 16 + 1820 * (a ** 12) * (b ** 4 + c ** 4)
        
        # 计算概率
        P = numerator / denominator
        
        # 输出结果,保留10位小数
        print(f"{P:.10f}")

if __name__ == "__main__":
    main()

Java版本:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int t = scanner.nextInt();  // 测试数据组数
        
        // 计算分母:16的16次方
        double denominator = Math.pow(16, 16);
        
        for (int i = 0; i < t; i++) {
            int a = scanner.nextInt();  // 铜粒概率分子
            int b = scanner.nextInt();  // 银粒概率分子  
            int c = scanner.nextInt();  // 金粒概率分子
            
            // 计算分子:
            // 1. Math.pow(a, 16): 16个沙砾全部掉落铜粒
            // 2. 1820 * Math.pow(a, 12) * (Math.pow(b, 4) + Math.pow(c, 4)):
            //    - 1820是组合数C(16,4)
            //    - 12个铜粒 + 4个银粒或金粒
            double numerator = Math.pow(a, 16) + 
                             1820 * Math.pow(a, 12) * (Math.pow(b, 4) + Math.pow(c, 4));
            
            // 计算概率
            double P = numerator / denominator;
            
            // 输出结果,保留10位小数
            System.out.printf("%.10f\n", P);
        }
        
        scanner.close();
    }
}
好了,各位码友,代码已经调试通过,文章也已commit,就等各位的push了。点赞不要 //TODO,关注务必 star!

写在后面:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

麦烤楽鸡翅

投喂作者,防止Ta饿晕在键盘前

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值