2020牛客寒假算法基础集训营2 C 算概率

题目描述
牛牛刚刚考完了期末,尽管牛牛作答了所有的n道题,但他也不知道有多少道题是正确的。

不过,牛牛知道第i道题目的正确率是p_{i}

牛牛想知道这n道题里,恰好做对0,1,2···n道题目的概率分别是多少,对10^{9}+7取模

10^{9}+7取模的含义是:对于一个b \neq 0的不可约分分数\frac{a}{b},存在q使得b\times q mod (10^{9}+7)=aq即为\frac{a}{b}10^{9}+7取模的结果

思路

首先可以看出这是一个概率题目,对于恰好0个对,就是每一个都错的概率相乘,对于恰好k个对,就是任选k个对的概率,乘以其余不对概率,最后求和。

思路没问题,但是如果想通过这样的方式AC,是不可能的,时间复杂度太大了。

可以往概率dp上面考虑,令f[i][j]的含义是,前i个题目对了j的概率,可以通过dp的手段,一步一步探索道f[n][k]f[n][k]就是一共n个题目恰好对了k个的概率,然后依次输出。

第一次接触概率dp,比赛的时候很懵

转移方程很简单,首先考虑f[i][j] 的来源,显然前i个对j个的概率可以有前面的i-1个对j个,然后当前这个错误,可以这么推到出来(前提是i-1\geq j),还可以是,前i-1个对了j-1的概率,乘以当前这个题目对了概率,依次递推即可,初始状态就是f[1][0]=第一个错误的概率,f[1][1]=第一个正确的概率。题目中说的取模10^{9}+7的意义可以不考虑,直接把给出的数字当作正确的概率,错误的概率是10^{9}+8-正确的概率,计算过程中对10^{9}+7取模就可以了

code

#include <bits/stdc++.h>
using namespace std;
#define mem(a, b) memset(a, b, sizeof a)
const int N = 2010;
const int mod = 1e9 + 7;
typedef long long ll;
ll f[N][N];
int n;
ll a[N];
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)scanf("%lld", a + i);
	mem(f, 0);
	f[1][1] = a[1];
	f[1][0] = mod + 1 - a[1];
	for (int i = 2; i <= n; i++){
		f[i][0] = f[i - 1][0] * (mod + 1 - a[i]) % mod;
		for (int j = 1; j <= i; j++){
			f[i][j] = f[i - 1][j] * (mod + 1 - a[i]) % mod + f[i - 1][j - 1] * (a[i]) % mod;
			f[i][j] %= mod;
		}
	}
	for (int i = 0; i <= n; i++){
		printf("%lld ", f[n][i]);
	}
	return 0;
}

 

posted @ 2020-02-07 14:14  correct  阅读(141)  评论(0)    收藏  举报