牛客练习赛26 B 烟花【DP+概率论】

链接

https://www.nowcoder.com/acm/contest/180/B
来源

牛客网
 

烟花

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
Special Judge, 64bit IO Format: %lld

题目描述

小a有个烟花,每个烟花代表着互不相同的颜色,对于第个烟花,它有的概率点燃,现在小a要去点燃它们,他想知道产生颜色的期望个数 及 产生恰好产生种颜色的概率

输入描述:

第一行两个整数
接下来一行个数,第个数表示第个烟花被点燃的概率

输出描述:

输出有两行
第一行表示产生不同颜色的期望个数

第二行表示产生恰好种颜色的概率

以换行符分割

示例1

输入

3 2
0.5 0.25 0.75

输出

1.5000
0.4062

说明

第二问样例解释:


相加得

备注:

对于的数据:
对于的数据:
输出均保留4位小数,若你的答案误差与std不超过即为正确

题解:由期望的定义可以知道期望=1*p1+1*p2+...+1*pn。求解恰好产生种颜色的概率使用动态规划。dp(i,j)表示使用前i种烟花,让其中j种烟花被点燃的概率。pi表示第i种烟花被点燃的概率,考虑第i种烟花,只有两种选择策略,被点燃或者不被点燃。

策略1:dp(i-1,j)*(1-pi)表示前i-1种烟花中有j种烟花被点燃且第j种烟花不被点燃的概率

策略2:dp(i-1,j-1)*pi表示前i-1种烟花中有j-1种烟花被点燃且第j种烟花被点燃的概率

那么状态转移方程为 dp(i,j)=dp(i-1,j)*(1-pi)+dp(i-1,j-1)*pi

优化空间复杂度:

由dp(i,j)=dp(i-1,j)*(1-pi)+dp(i-1,j-1)*pi 可知只要保证在推dp(i,j)时dp(i-1,j)和dp(i-1,j-1)仍是上一层的结果就行,这和01背包问题一样,只要j从大到小推即可

AC的C++代码:

#include<iostream>

using namespace std;
const int N=100005;

double dp[N],p[N];

int main()
{
	int n,k;
	double sum=0; 
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){ 
	  scanf("%lf",&p[i]);
	  sum+=p[i];
	}
	dp[0]=1.0;
	for(int i=1;i<=n;i++){//考虑前i个物品 
	  for(int j=k;j>=1;j--)//j要从大到小推
	    dp[j]=dp[j]*(1.0-p[i])+dp[j-1]*p[i];
	  dp[0]*=(1-p[i]);//dp[0]表示一种都没点燃的概率
    }
	printf("%.4lf\n%.4lf\n",sum,dp[k]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/SongBai1997/article/details/82631006
今日推荐