zoukankan      html  css  js  c++  java
  • Luogu4040 AHOI/JSOI2014 宅男计划 贪心、二分、三分

    传送门


    仍然对“为什么这个函数单峰”的问题毫无理解

    首先,对于保质期又低、价格又贵的食物,我们显然不需要购买它。所以如果设(pri_i)表示保质期不小于(i)的所有食品中价格最低的食品的价格,那么(pri)数组显然单调不降。

    考虑如果我们要直接去做比较麻烦,可是如果我们知道点外卖的次数,就很好计算了。

    假设我们知道了我们总共要买(x)次外卖,不难知道这(x)次外卖点的食物能够坚持的时间的极差不会超过(1),否则可以用多的补少的,在不降低总坚持时间的情况下降低总价格(因为(pri)单调不降)。

    假设(x)次外卖坚持的时间为(K)(K+1),那么可以先二分出(K),然后将剩下的钱尽可能多的买(pri_{K+1})

    现在,确定点外卖的次数就可以求得对应的能够坚持的时间,问题就是如何求最长的时间。不难发现点外卖的次数与坚持的时间对应的函数是一个单峰函数,直接上三分就完事了。

    有没有神仙会证这个函数单峰啊QAQ

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<ctime>
    #include<cctype>
    #include<algorithm>
    #include<cstring>
    #include<iomanip>
    #include<queue>
    #include<map>
    #include<set>
    #include<bitset>
    #include<stack>
    #include<vector>
    #include<cmath>
    #define INF 0x3f3f3f3f
    #define int long long
    #define PII pair < int , int > 
    #define st first
    #define nd second
    //This code is written by Itst
    using namespace std;
    
    inline int read(){
        int a = 0;
        char c = getchar();
        bool f = 0;
        while(!isdigit(c) && c != EOF){
            if(c == '-')
                f = 1;
            c = getchar();
        }
        if(c == EOF)
            exit(0);
        while(isdigit(c)){
            a = (a << 3) + (a << 1) + (c ^ '0');
            c = getchar();
        }
        return f ? -a : a;
    }
    
    vector < PII > tg;
    vector < PII > :: iterator it , it1;
    int M , F , N , sum[210];
    bool f[210];
    
    inline int calcSum(int dir){
        it = lower_bound(tg.begin() , tg.end() , PII(dir , -1));
        int t = it - tg.begin();
        if(t && !f[t - 1] || (t ? sum[t - 1] : 0) + 1.0 * tg[t].nd * (dir - (t ? tg[t - 1].st : -1)) > M)
            return 2e18;
        return (t ? sum[t - 1] : 0) + tg[t].nd * (dir - (t ? tg[t - 1].st : -1));
    }
    
    inline int calc(int x){
        int s = M - x * F , L = -1 , R = tg[N - 1].st;
        while(L < R){
            int mid = L + R + 1 >> 1;
            calcSum(mid) <= s / x ? L = mid : R = mid - 1;
        }
        s -= calcSum(L) * x;
        if(L == tg[N - 1].st)
            return (L + 1) * x;
        it = lower_bound(tg.begin() , tg.end() , PII(L + 1 , -1));
        return (L + 1) * x + s / it->second;
    }
    
    inline bool check(int mid){
        return calc(mid) >= calc(mid + 1);
    }
    
    signed main(){
    #ifndef ONLINE_JUDGE
        //freopen("in" , "r" , stdin);
        //freopen("out" , "w" , stdout);
    #endif
        M = read();
        F = read();
        N = read();
        for(int i = 1 ; i <= N ; ++i){
        	int a = read() , b = read();
        	tg.push_back(PII(b , a));
        }
        sort(tg.begin() , tg.end());
        for(it = --tg.end() , it1 = it , --it1 ; it != tg.begin() ; --it , it1 = it , --it1)
            if(it->nd < it1->nd)
                it1->nd = it->nd;
        for(it = tg.begin() , it1 = it , ++it1 ; it1 != tg.end() ; ++it , it1 = it , ++it1)
            if(it->st == it1->st)
                it1->nd = it->nd;
        for(int i = 0 ; i < N ; ++i)
            if((i == 0 ? 0 : sum[i - 1]) + 1.0 * tg[i].nd * (tg[i].st - (i == 0 ? -1 : tg[i - 1].st)) <= M){
                f[i] = 1;
                sum[i] = (!i ? 0 : sum[i - 1]) + tg[i].nd * (tg[i].st - (!i ? -1 : tg[i - 1].st));
            }
            else
                break;
        int L = 1 , R = M / F;
        while(L < R){
        	int mid = (L + R) >> 1;
        	check(mid) ? R = mid : L = mid + 1;
        }
        cout << calc(L);
        return 0;
    }
    
  • 相关阅读:
    POJ 2352 &amp;&amp; HDU 1541 Stars (树状数组)
    SSH三大框架的工作原理及流程
    稀疏表示
    Linux程序设计学习笔记----多线程编程线程同步机制之相互排斥量(锁)与读写锁
    [面经] 南京SAP面试(上)
    JAVA数组的定义及用法
    花指令
    计算机认证考试种类
    《C语言编写 学生成绩管理系统》
    spice for openstack
  • 原文地址:https://www.cnblogs.com/Itst/p/10331691.html
Copyright © 2011-2022 走看看