XDOJ 1020 ACMer去刷题吧(基础dp)
题目描述
刷题是每个ACMer必由之路,已知某oj上有n个题目,第i个题目小X能做对的概率为Pi(0<=Pi<=1,1<=i<=n) 求小X至少做对k道题的概率
输入
第一行输入一个正整数t,(t<=20),表示有t组测试样例。 第二行输入正整数n,k,(1<=n,k<=1000) 第三行输入n个小数,分别为Pi(1<=i<=n,0<=Pi<=1),表示小X做对第i个题目的概率。
输出
输出小X至少做对k道题的概率,并换行(保留4位小数)
样例输入
2
1 1
0.5
3 2
0.3 0.2 0.1
样例输出
0.5000
0.0980
提示
题目大意:
这题就是说,给你一个每道题做对的概率,然后,让你求出来至少做对k道题的概率是多少.
解题思路:
其实不难,只要推出来dp[i][j]玩就好了,一开始推了一会,,少了个条件(Q神给窝补上去了)
状态:dp[i][j]表示的是有i道题,作对j道题的概率。
初始状态:dp[0][0] = 1,dp[0][1] = 0;
状态转移方程:dp[i][j] = dp[i-1][j-1]*p[i]+dp[i-1][j]*(1-p[i]);
dp[i][0] = (1-p[i])*dp[i-1][0]
最后只要求出来sum+=dp[n][k]+dp[n][k+1]+dp[n][k+2]+...+dp[n][n];
代码:
1 # include<cstdio> 2 # include<iostream> 3 4 using namespace std; 5 6 # define MAX 1234 7 8 double p[MAX]; 9 double dp[MAX][MAX]; 10 int n,k; 11 12 int main(void) 13 { 14 int t;scanf("%d",&t); 15 while ( t-- ) 16 { 17 scanf("%d%d",&n,&k); 18 for ( int i = 1;i <= n;i++ ) 19 { 20 scanf("%lf",&p[i]); 21 } 22 dp[0][0] = 1; 23 dp[0][1] = 0; 24 for ( int i = 1;i <= n;i++ ) 25 { 26 dp[i][0] = (1-p[i])*dp[i-1][0]; 27 } 28 for ( int i = 1;i <= n;i++ ) 29 { 30 for ( int j = 1;j <= n;j++ ) 31 { 32 dp[i][j] = (1-p[i])*dp[i-1][j]+p[i]*dp[i-1][j-1]; 33 } 34 } 35 double sum = 0; 36 for ( int i = k;i <= n;i++ ) 37 { 38 sum+=dp[n][i]; 39 } 40 printf("%.4lf\n",sum); 41 42 } 43 44 45 return 0; 46 }