hdu 5089 使做对k-1题最大概率的选题方案

23 篇文章 0 订阅
4 篇文章 0 订阅

http://acm.hdu.edu.cn/showproblem.php?pid=5089

给出N道难度递增的题目,难度用可能做出的百分比表示,选出K道题目使得做出K-1道题目的概率最大。
选k题的情况下做出k-1的概率为所有(1-p)*p*p...的和,直接尝试转化这个式子的效果并不明显。
换个思路,假设最优解已经包含了k-1个了,现在来选取最后一个。K-1个全部做出的概率是Pall(k−1),有一道为做出的概率是Pless(k−1),现在选取的是PCk,那么做出K-1道的概率是
Pall(k−1)∗(1−P[PCk])+Pless(k−1)∗P[PCk]=
Pall(k−1)+P[PCk]∗(Pless(k−1)−Pall(k−1))
这是一个关于PCk的一次函数,如果Pless(k−1)−Pall(k−1)为正,选取最大的PCk,否则选取最小的。

那么我们每次选取的时候一定是选择剩下的最大或最小,那么说明答案一定是选取两边的概率,枚举比较一下就可以算出最大的概率了。
但是要求的是字典序最小的。左边不用管,对于右边,如果存在相同的value,应该选取index较小的。然后随便搞下就ok了。

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
#define RD(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d%d",&x,&y)
#define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define clr0(x) memset(x,0,sizeof(x))
#define clr1(x) memset(x,-1,sizeof(x))
#define eps 1e-9
const double pi = acos(-1.0);
typedef long long LL;
typedef unsigned long long ULL;
const int modo = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const int inf = 0x3fffffff;
const LL _inf = 1e18;
const int maxn = 55,maxm = 1<<12;
int n,k;
bool vis[maxn];
double p[maxn];
int pos[maxn],s[maxn];
int main()
{
    int _,_g;RD(_);
    while(_--){
        RD2(n,k);
        clr0(vis);
        for(int i = 0;i < n;++i){
            RD(s[i]);
            p[i] = ((double)s[i])/100.0;
        }
        double mx = 0;
        for(int g = 0;g <= k;++g){//选择前g个和后k - g个
            double _p,res = 0;
            int cnt = 0;
            for(int i = 0;i < g;++i)
                pos[cnt++] = i;
            for(int i = 1;i <= k - g;++i)
                pos[cnt++] = n - i;
            for(int i = 0;i < cnt;++i){
                _p = 1;
                for(int j = 0;j < cnt;++j){
                    if(j != i)
                        _p *= p[pos[j]];
                    else
                        _p *= (1 - p[pos[j]]);
                }
                res += _p;
            }
            if(mx - res < eps){
                mx = res;
                _g = g;
            }
        }
        for(int i = 0;i < _g;++i)
            vis[i] = 1;
        for(int i = n - (k - _g);i < n;++i){
            for(int j = i;j >= 0;--j){
                if(vis[j] || s[j] > s[i])
                    break;
                _g = j;
            }
            vis[_g] = 1;
        }
        _g = 1;
        for(int i = 0;i < n;++i)
            if(vis[i])
                printf("%d%c",i+1," \n"[_g == k]),_g++;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值