CF 443D. Andrey and Problem 贪心 or DP

题意:n个盒子,第i个盒子有奖品的概率为a[i].问选若干个盒子后,正好获得一个奖品的概率最大是多少?
n<=100,0<=a[i]<=1.0


假如选的是子集s,一共k个物品.则正好中一个奖品的概率为 tot=(p1*q2*..qk)+(q1*p2*..qk)+...(q1*q2...pk).
现在设dp[i][j] 前i个物品选j个正好中一个奖品的最大概率.
dp[i][j]=max(dp[i-1][j],dp[i-1][j-1]*q[i]+(q1*q2..q[k-1]*p[k])) dp[i-1][j-1]相当于选j-1个时的tot.

现在只要把[q[1]..q[j-1]]求出来即可.求方案也可以递推. 总共O(n^3).


正解是贪心:从概率大的往下选 若添加一下一个能使答案增加 则加入下一个.O(nlogn) 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e2+5;
int n;
double p[N],q[N],dp[N][N];
vector<double> v[N][N];
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>p[i],q[i]=1-p[i];
    dp[0][0]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
        {
            dp[i][j]=dp[i-1][j];
            v[i][j]=v[i-1][j];

            double res=1;
            for(int k=0;k<v[i-1][j-1].size();k++)
                res*=v[i-1][j-1][k];
            res*=p[i];
            if(dp[i][j]<dp[i-1][j-1]*q[i]+res)
            {
                dp[i][j]=dp[i-1][j-1]*q[i]+res;
                v[i][j]=v[i-1][j-1];
                v[i][j].push_back(q[i]);
            }
        }
    }
    double ans=0;
    for(int i=1;i<=n;i++)
        ans=max(dp[n][i],ans);
    printf("%.10lf\n",ans);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值