【BZOJ3874】[AHOI&JSOI2014]宅男计划(贪心,三分)

博客围绕【BZOJ3874】[AHOI&JSOI2014]宅男计划展开,猜想最长天数和购买外卖总次数呈单峰关系,也可退火处理。已知购买总次数时,将外卖按价格排序,优先买便宜且未过期的,对最便宜外卖每次买其过期天数对应的份数,后续外卖类似处理。

【BZOJ3874】[AHOI&JSOI2014]宅男计划(贪心,三分)

题面

BZOJ
洛谷

题解

大力猜想一最长的天数和购买外卖的总次数是单峰的。感性理解一下就是买\(0\)次是\(0\),买\(inf\)次也是\(0\),在中间某次可能取到最优值。然而这样子可能是多峰的,所以也可以退火处理。
现在假装我们知道了购买外卖的总次数\(k\),那么我们的问题就变成了如何确定每种外卖购买方案。
首先将所有外卖按照价格排序,显然只要没有过期那么一定会购买尽可能多的更便宜的外卖。
假设对于最便宜的外卖,其过期的天数是\(s\),那么我们一定会在每次购买的时候都买\(s\)份,那么接下来的每一份外卖都是类似的处理。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
inline ll read()
{
    ll x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
ll m,F,n;
struct Food{ll p,s;}p[250];
bool operator<(Food a,Food b){return a.p<b.p;}
ll Calc(ll c)
{
    ll M=m-F*c,ans=0,t=0;if(M<=0)return 0;
    for(int i=1;i<=n;++i)
        if(p[i].s>t)
        {
            ll d=p[i].s-t;
            if(1.0*p[i].p*c*d<=M)ans+=c*d,M-=p[i].p*c*d;
            else{ans+=M/p[i].p;break;}
            t=p[i].s;
        }
    return ans;
}
int main()
{
    m=read();F=read();n=read();
    for(int i=1;i<=n;++i)p[i].p=read(),p[i].s=read()+1;
    sort(&p[1],&p[n+1]);
    ll l=0,r=m/F,ret=0;
    while(r-l>=5)
    {
        ll p0=l+(r-l+1)/3,p1=r-(r-l+1)/3;
        ll d0=Calc(p0),d1=Calc(p1);
        if(d0<=d1)l=p0;else r=p1;
    }
    for(ll i=l;i<=r;++i)ret=max(ret,Calc(i));
    printf("%lld\n",ret);
    return 0;
}

转载于:https://www.cnblogs.com/cjyyb/p/10572841.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值