bzoj 3874: [Ahoi2014&Jsoi2014]宅男计划

三分+贪心检验  (注意check的时候,多用/法,不要炸long long)

jyy可以生存的时间 与 买的次数 成一个上凸的单峰函数

证明:

如果买的太多,光小费就给不起

如果买的太少,又不能充分利用多种食物

所以可以三分 买的次数

贪心check:

先把保质期短而且又贵的食物去掉

然后剩下的食物一定是保质期越长越贵

那就从保质期短到长一直买到不能买为止

 

 

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=1006;

struct son
{
    ll t,w;
}ji[N],q[N];
int con;
bool ok_t(son a,son b)
{
    if(a.t==b.t)
        return a.w<b.w;
    return a.t<b.t;
}
bool ok_w(son a,son b)
{
    if(a.w==b.w)
        //return a.t>b.t; //wrong reason:不能a.t>b.t,因为有可能用到
        return a.t<b.t;
    return a.w<b.w;
}

int n;
ll M,F;

ll check(ll x)
{
    ll ans=0,temp,le=M-F*x,fina,can;
    if(le<0)
        return 0;
    for(int i=1;i<=con;++i)
    {
        if(le<0)
            break;
        temp=le/q[i].w;
        /*fina=min(temp,q[i].t*x-ans );
        if(fina<0)  //炸long long了
            while(1);*/
        can=(temp+ans-1)/x+1;
        if(can>q[i].t)   // T_M_D 炸long long
            fina=q[i].t*x-ans;
        else
            fina=temp;
        ans+=fina;
        le-=fina*q[i].w;
    }
    return ans;
}

ll work()
{
    ll ans=0;
    ll l=1,r=M/(F+q[1].w),mid,midmid,vmid,vmidmid;
    while(l+15<=r)
    {
        mid=l+((r-l)/3);
        midmid=r-((r-l)/3);
        vmid=check(mid);
        vmidmid=check(midmid);
        if(vmid>vmidmid)
        {
            r=midmid;
            if(ans<vmid)
                ans=vmid;
        }
        else
        {
            l=mid;
            if(ans<vmidmid)
                ans=vmidmid;
        }
    }
    for(ll i=l;i<=r;++i)
    {
        vmid=check(i);
        if(ans<vmid)
            ans=vmid;
    }
    return ans;
}

int main(){

    //freopen("in.in","r",stdin);

    scanf("%lld%lld%d",&M,&F,&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%lld%lld",&ji[i].w,&ji[i].t);
        ++ji[i].t;
    }
    sort(ji+1,ji+1+n,ok_w);
    con=0;
    q[++con]=ji[1];
    for(int i=2;i<=n;++i)
        if(ji[i].t>q[con].t)
            q[++con]=ji[i];
    //sort(q+1,q+1+con,ok_t); // 已经是按时间排序了....
    cout<<work();
}
bzoj_3874

 

原文地址:https://www.cnblogs.com/A-LEAF/p/7623182.html