牛客寒假算法基础集训营2题解(C题)

算概率

https://ac.nowcoder.com/acm/contest/3003/C

图片说明
对于这道C题,他要我们求的是在n道题目中,有0,1,2,3....n道题目做对的概率,然后分别按隔一个空格输出对1e9+7求模后的结果,在看了出题人的题解后,我一开始也十分困惑,因为出题人或其他提交的同学代码都没有解释,然后,我就花了一个小时在纸上模拟,终于我搞懂了,希望接下来的可以对报名参加了比赛但还没理解该题的同学有所帮助。
首先,我来解释一下下面几个代码的含义:
在代码中,我们先定义一个二维数组,f[2020][2020],对于f[i][j]的含义是在当前的i道题目中,恰好有j道题目做对的概率(以下所说的概率都是求模后的结果)。

const int mod=1e9+7;
(mod+1-p[i])%mod

该式的意义是第i题做错的概率。为了方便计算,我们都是假设分式a/b当中分母b的值为1,即b=1,(因为任何分式都可以化为分母为1的式子,当然,分子a可以为小数。所以由b*q%(1e9+7)=a;这里b=1,q就是我们输入的p[i],可得p[i]=kmod+a;即a=p[i]-kmod;那么求对应的错误的概率就是用1-a,即1-a=(kmod+1-p[i])%mod=(mod+1-p[i])%mod,因为分母b为1

f[i][0]=f[i-1][0]*(mod+1-p[i])%mod;

那么,该行代码的意思就是当前有i道题目,有0道做对的概率等于i-1道题目中有0道题目做对的概率再乘以第i道题目做错的概率

f[i][j]=(f[i-1][j]*(mod+1-p[i])%mod+f[i-1][j-1]*p[i])%mod;

所以,这个代码就不难理解了。即要求i道题目中,j道题目做对的概率,就是相当于求i-1道题目中j道题目做对的概率乘以第i道题目做错的概率,再加上i-1道题目中j-1道题目做对的概率乘以第i道题目做对的概率(有点绕哈,希望大家好好理解)。其实这个算法思想和求排列组合的思想不谋而和。
接下来,我就给出代码了哦!

#include<iostream>
using namespace std;
const int mod=1e9+7;
long long p[2020],f[2020][2020];
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>p[i];
    }
    f[0][0]=1;  //0道题目做对0题的概率肯定是1 
    for(int i=1;i<=n;i++){
        //从题目1开始进行枚举到n 
        f[i][0]=f[i-1][0]*(mod+1-p[i])%mod;  //求有i道题目做对0道题目的概率 
        for(int j=1;j<=i;j++){
            f[i][j]=(f[i-1][j]*(mod+1-p[i])%mod+f[i-1][j-1]*p[i])%mod;  
            //由类推求出当前有i道题目中,做对j道题目的概率 
            //这里j从1开始进行枚举到当前循环下的i,
            //所以在这个过程中就求出来了有i题的情况下,做对0到i道题目的概率 
        }
    }
    for(int i=0;i<=n;i++){
        cout<<f[n][i];
        if(i<n)  cout<<" "; //为了按题目格式输出,希望这个方法还没学到的同学可以记住
    }
    return 0;
}

好了,这题的解题思路大概就是这样了,希望对刚接触小伙伴们有所帮助,接下来我还会继续给出另外几题的题解的,谢谢大家。我的博客目前主要是针对萌新的,(因为本人也是萌新一枚,所以更能理解)所以如果有牛客的大佬无意间看到希望可以提出宝贵的建议,当然,如果有不解的可以在下方留言,我会尽力去帮忙的。
附:
牛客寒假算法基础训练营2题解F题
https://blog.nowcoder.net/n/a6eb59c66675495da6d5d4697e5d7cf3
牛客寒假算法基础训练营2题解D题https://blog.nowcoder.net/n/0140a8622eba4346b4811ea9c0749312

全部评论
题目说的输入的是概率求模后的值,而p[i]-kmod就是真正的概率,而我们最后的要输出的就是求模后的值。
1 回复 分享
发布于 2020-02-08 10:43
请问,p[i]=mod+a,这一步可以再讲讲吗,没理解到,谢谢
1 回复 分享
发布于 2020-02-07 19:41
这一题 可以让j从0开始就可以了 上边那一语句可以删除 可以简化成这样 for(int i=1;i<=n;i++) { for(int j=0;j<=i;j++) { pp[i][j]=(pp[i-1][j]*(mod+1-p[i])+pp[i-1][j-1]*p[i])%mod; } }
点赞 回复 分享
发布于 2020-02-12 17:11
啊,我又来了,对不起,我太菜了。为啥,正确的概率是p[i]啊,怎么不是你算的p[i]-kmod。我想你是不是又将它模了下,只是为什么又要模啊。谢谢
点赞 回复 分享
发布于 2020-02-08 10:20
xie xie
点赞 回复 分享
发布于 2020-02-07 19:37
第二重循环那个地方是不是可以优化一下,j<=i就行了,不需要<=n
点赞 回复 分享
发布于 2020-02-07 18:42
理解了,谢谢
点赞 回复 分享
发布于 2020-02-07 16:35

相关推荐

不愿透露姓名的神秘牛友
2025-11-27 14:30
点赞 评论 收藏
分享
评论
47
5
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务