G.Graduation Guarantee
题目链接:https://codeforc.es/gym/104030/problem/G
题目大意:有n道题,要得k分,每道题做对+1分做错-1分,可以选择做或者不做,每道题做对的概率是pi,求能到达k分的最大概率是多少
思路:贪心+期望dp
先将概率从大到小进行排序,若该题做对的概率较小的话,不选这题得到k分的概率要比选这题的高,所以用dp[i][j]跑出前i题做对j题的概率是多少,然后遍历找出最大值。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e3 + 50;
double dp[N][N];
// 前i个题中选 对了j题的概率
double p[N];
void solve() {
int n,k;
cin >> n >> k;
for (int i=1; i<=n; ++i) cin >> p[i];
sort(p+1,p+1+n,greater<double>() );
dp[0][0] = 1;
for (int i=1; i<=n; ++i){
dp[i][0] = (1-p[i]) *dp[i-1][0];
}
for (int i=1; i<=n; ++i){
for (int j=1; j<=n; ++j){
dp[i][j] = p[i]*dp[i-1][j-1] + (1-p[i])*dp[i-1][j];
}
}
double ans = 0;
for (int i=k; i<=n; ++i) {
double u=0;
for(int j=i-(i-k)/2;j<=i;j++){ //(i-k)/2为最多只能错k题
u+=dp[i][j];
}
ans=max(ans,u);
}
cout<<ans;
}
int main() {
ios::sync_with_stdio(false),cin.tie(nullptr);
cout.tie(nullptr);
int t = 1;
//cin >> t;
while (t--) {
solve();
}
return 0;
}