zoukankan      html  css  js  c++  java
  • Offer收割_5

    训练 投入 欲望。  ---贾森博尔特

    第一题:二分枚举答案,check时候模拟一下即可。

        时间复杂度: O(n*logn)。

    第二题:

    描述

    小Hi在虚拟世界中有一只小宠物小P。小P有K种属性,每种属性的初始值为Ai。小Ho送给了小Hi若干颗药丸,每颗药丸可以提高小P指定属性1点。通过属性值,我们可以计算小P的强力值=(C1(1/B1))*(C2(1/B2))*...*(CK(1/BK)),其中Ci为小P第i项属性的最终值(Ai+药丸增加的属性)。 已知小Ho送给小Hi的药丸一共有N颗,问小P的强力值最高能够达到多少?

    输入

    第一行包含两个整数N,K,分别表示药丸数和属性种数。

    第二行为K个整数A1 - AK,意义如前文所述。

    第三行为K个整数B1 - BK,意义如前文所述。

    对于30%的数据,满足1<=N<=10, 1<=K<=3

    对于100%的数据,满足1<=N<=100000, 1<=K<=10

    对于100%的数据,满足1<=Ai<=100, 1<=Bi<=10

    输出

    输出小P能够达到的最高的强力值。

    只要你的结果与正确答案之间的相对或绝对误差不超过千分之一,都被视为正确的输出。

    样例输入

    5 2
    1 1
    3 2

    样例输出

    2.88

    解体思路:

    1.一开始yy的各种结论,发现不准。最后,为了搞定小数据集,暴力将n分解成k份,然后求解。这样可以过掉30%的小数据。

    //
    //  main.cpp
    //  ProjectC
    //
    //  Created by LiJinxu on 16/8/13.
    //  Copyright © 2016年 LiJinxu-NEU. All rights reserved.
    //
    
    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <math.h>
    #include <vector>
    
    using namespace std;
    
    const int INF = 0x3f3f3f3f;
    const int Maxn = 100001;
    int n, k;
    double a[Maxn], b[Maxn];
    vector<pair<double, double>>rec;
    
    bool cmp(pair<double, double> &p1, pair<double, double> &p2){
        if(p1.first == p2.first){
            return p1.second < p2.second;
        }
        return p1.first < p2.first;
    }
    
    void divideN2Kparts(int pos, int left, int *path, vector<vector<int>>&rec)
    {
        if(left == 0 && pos == k){
            vector<int>tmp;
            for(int i = 0; i < k; i ++)
                tmp.push_back(path[i]);
            rec.push_back(tmp);
            return ;
            
        }else if(left && pos >= k){
            return ;
        }
        for(int i = n; i >= 0; i --){
            if(left < i) continue;
            left -= i;
            path[pos] = i;
            pos ++;
            divideN2Kparts(pos, left, path, rec);
            pos --;
            path[pos] = 0;
            left += i;
        }
    }
    
    void smallSolution()
    {
        vector<vector<int>>rec;
        int path[Maxn];
        for(int i = 0;i < k; i ++)
            path[i] = 0;
        divideN2Kparts(0, n, path, rec);
        double fAns = 0;
        for(int i = 0; i < rec.size(); i ++){
            double ans = 1;
            for (int j = 0; j < rec[i].size(); j++) {
                ans *= pow(a[j] + (double) rec[i][j], (1.0/b[j]));
            }
            if(fAns < ans)
                fAns = ans;
        }
        printf("%.2lf
    ",fAns);
    
    }
    int main() {
        cin>>n>>k;
        for(int i = 0; i < k; i ++){
            scanf("%lf", &a[i]);
        }for(int i = 0; i < k; i ++)
            scanf("%lf", &b[i]);
        smallSolution();
        return 0;
    }

    2.全解方案:

      根据题意强力值P=(C1(1/B1))*(C2(1/B2))*...*(CK(1/BK)), Ci = (Ai + Xi), N = X0 + .. + Xk; 目标是:让P最大。因为是乘法求最大值问题,我们通过两边去对数log得到:

      logP = (1/B1)logC1 + (1/Bi)logCi + (1/Bk)logCk 。 Ci = Ai + Xi。 这样,为了使P最大,我们只需要每次增量(△x = 1)使得整体增量最大即可:max(1/Bi * log(Ai + 1) - 1/Bi * log(Ai))。因为每次增加1,也就是增加到C1 - Ck中的某一项,使得增益最大即可。这里就能够体现出加法的好处,易于衡量结果。 

      最后,只需要使用一个数据结构(priority_queue)来动态维护每次给对应项增加1(满足收益最大)的过程就好了。 时间复杂度:O(n*logn);

      这道题的关键是:增量为1,1个1个的考虑,而不是像我开始解决小规模数据集的思路,上来直接把n分成k份这样整体考虑。k在[1,10]很小,用优先队列维护开销不大。

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <algorithm>
    #include <math.h>
    #include <queue>
    #include <vector>
    #include <map>
    #define INF 0x3f3f3f3f
    
    using namespace std;
    
    const int Maxn = 100001;
    int n, k;
    double a[Maxn];
    struct node{
        double x, y;
        int id;
        bool operator <(const node &p)const{
            return 1.0 / y * (log(x + 1) - log(x)) < 1.0 / p.y * (log(p.x + 1) - log(p.x));
        }
    }rec[Maxn];
    
    priority_queue<node>p_que;
    
    int main()
    {
        cin>>n>>k;
        for(int i = 0; i < k; i ++){
            scanf("%lf", &a[i]);
            rec[i].x = a[i];
            rec[i].id = i;
        }
        for(int i = 0; i < k; i ++)
            scanf("%lf", &rec[i].y);
        for(int i = 0; i < k; i ++)
            p_que.push(rec[i]);
        for(int i = 0; i < n; i ++){
            node p = p_que.top();
            p_que.pop();
            p.x ++;
            a[p.id] ++;
            p_que.push(p);
        }
        double ans = 1.0;
        for(int i = 0; i < k; i ++){
            ans *= pow(a[i], 1.0/rec[i].y);
        }
        printf("%lf
    ",ans);
        //system("pause");
        return 0;
    }

      最后,关于优先队列的运算符重载,只能重载<。其他运算符会出错。return x > a.x //x小的在前。return x < a.x //x大的在前。

  • 相关阅读:
    vim编辑器介绍
    Linux基本命令
    Linux之文档与目录结构
    远程连接Linux
    VMware与Centos系统安装之重置root密码
    关于学习观
    mysql行转列,函数GROUP_CONCAT(expr)
    <a>超链接标签,<button>按钮标签,实现返回跳转
    2019年10月20日第一次参加自学考试
    disabled属性对form表单提交的影响
  • 原文地址:https://www.cnblogs.com/luntai/p/5772128.html
Copyright © 2011-2022 走看看