bzoj 3874: [Ahoi2014]宅男计划

[AHOI2014/JSOI2014]宅男计划:

\(solution:\)

看到这一题题面,莫名想到了(蔬菜),于是莫名开始恐慌。考场上只知道有个贪心计算快递小哥来一次,我要买能活n天的最小花费,却没想到还有一个三分法来枚举快递小哥来的次数!

首先我们可以脑补一下,快递小哥来的次数,和宅男活的总天数是成一个二次函数关系的。就像快递小哥来的次数少,那宅男多数的钱只能分到这么少的购买次数中,因为便宜的保质期短,每次必然会买一些保质期长价格贵的食物;当快递小哥来的次数多了,那我的钱可以分配到很多次购买机会中,是可以每次买些便宜的,可是你就会发现钱不多了(都给快递小哥付运费了!)所以我们三分找到中间的那一个平衡点(合理的购买次数能(钱尽其用)活得更久!!)

这是三分,那本题贪心贪在哪儿呢?我们读题发现,他给你的食品中肯定有一些垃圾食品(价格贵,保质期又短),我们可以进行筛选:单调队列,先将食品按保质期从大到小排序,然后放入以价格单调增的队列中去(因为后面放进取得食品保质期一定更长(排了序的),一但价格还比前一个低,就可以取代前一个食品)

然后还有一个贪心,就是在\(check()\)函数中,计算能活的最长天数时,只要在保质期内,我一定买最便宜的。就像我现在经筛选后有两个食品,一个保质期为5,价格为4,另一个保质期为8,价格为7,那我\([1,6]\)天一定买第一个,\([7,9]\)天一定买第二个!因为我们单调栈中时间从小到大,所以每次算活得最长天数时复杂度$O(n)
$再加上三分的复杂度,本题刚好够用!

然后对代吗做个解释:因为根据题意,保质期为1天的食品,可以留两天!!!(被这个坑惨了)所以我们在读入时干脆就给保质期加一,这样方便运算!然后解释一下我的\(check()\)函数:

  1. 我的\(check()\)买东西时,是同步的,如果买一个食品,那快递小哥来的\(x\)次都买这个食品(那个\(if\)除外)
  2. \(left:\)我还剩下的钱的数量,(因为特性1,所以每一次都要减去我买的食品的价格乘以它的数量再乘以\(x\)天)
  3. \(now:\)我同步买东西能同步维持的天数目前是多少
  4. \(day:\)我有几天需要买这一种食品(如果没有足够的钱贪心的买,就会转到\(if\)中去)
  5. \(tot:\)我总共能维持多少天
  6. \(if(now<b[i].t):\)我没足够的钱来\(x\)天同步买一个东西,那我能买几天买几天,然后$return $

接下来一切以代码为准:

\(code:\)

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>

#define ll long long
#define db double
#define inf 0x7fffffff
#define rg register int

using namespace std;

struct su{
    ll v,t;
}a[215],b[215];

ll n,top;
ll ans,m,f;//如题

inline ll qr(){//快读,可以忽略
    char ch;
    while((ch=getchar())<'0'||ch>'9');
    ll res=ch^48;
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+(ch^48);
    return res;
}

inline bool cmp(su x,su y){return x.t<y.t;}

inline ll check(ll x){
    ll left=m-x*f,now=0,day,tot=0;//剩余的钱,每一次买的食物能维持几天,我还有几天需要买这个食物,总共能维持多少天
    if(left<0)return 0;
    for(rg i=1;i<=top;++i){//快递小哥来的x次都买这种食物
        day=min(b[i].t-now,left/(b[i].v*x));//每一次都买几个
        now+=day; tot+=day*x; left-=b[i].v*day*x;//进行统计转移
        if(now<b[i].t){tot+=left/b[i].v;break;}//剩余的钱不能支持每一次都买了,就能卖几次买几次,然后return
    }return tot;
}

int main(){
    //freopen("food.in","r",stdin);
    //freopen("food.out","w",stdout);
    m=qr();f=qr();n=qr();
    for(rg i=1;i<=n;++i)
        a[i]=su{qr(),qr()+1};
    sort(a+1,a+n+1,cmp); //按时间排序!!!(非价值)
    for(rg i=1;i<=n;b[++top]=a[i],++i)
        while(top&&a[i].v<=b[top].v)--top;//用单调栈进行食品筛选(加速)
    ll l=1,r=m/(f+b[1].v),mid1,mid2,tot,s1,s2;//r的值可以算出来
    while(l<=r){ //三分法求峰值
        tot=r-l+1,mid1=l+tot/3,mid2=l+tot*2/3;
        s1=check(mid1);s2=check(mid2);
        ans=max(ans,(s1<s2?l=mid1+1,s2:r=mid2-1,s1));//究极的三目运算压行
    }printf("%lld\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/812-xiao-wen/p/10332544.html

时间: 2024-08-26 13:46:49

bzoj 3874: [Ahoi2014]宅男计划的相关文章

BZOJ 3874([Ahoi2014]宅男计划-dp+三分法+贪心)

3874: [Ahoi2014]宅男计划 Time Limit: 1 Sec  Memory Limit: 256 MB Submit: 66  Solved: 24 [Submit][Status][Discuss] Description [故事背景] 自从迷上了拼图,JYY就变成了个彻底的宅男.为了解决温饱问题,JYY 不得不依靠叫外卖来维持生计. [问题描述] 外卖店一共有N种食物,分别有1到N编号.第i种食物有固定的价钱Pi和保质期Si.第i种食物会在Si天后过期.JYY是不会吃过期食

bzoj3874[Ahoi2014]宅男计划

bzoj3874[Ahoi2014]宅男计划 题意: n种食物,每种有价钱和保质期.每次叫外卖要F元,可以购买任意多份食物.共有m元,问一共能过多少天使得每天都能吃到一份不过期的食物. 题解: 先排序+单调队列去掉那些价钱贵保质期反而短的外卖,剩下的队列按保质期从短到长排(也就是价钱从便宜到贵排).然后有结论:生存天数为以叫外卖次数为自变量的单峰函数.因此三分叫外卖次数(注意上界为m/最便宜外卖的价钱),如何根据叫外卖次数求生存天数呢?又有结论:每次叫外卖间隔时间越平均越优.设叫外卖次数为k,从

【BZOJ3874】[Ahoi2014]宅男计划【贪心】【模拟退火 / 三分法】

[题目链接] 可以发现,购买方案是有周期的,周期个数即为购买次数. 对于固定的购买次数,我们可以贪心的求出最多存活多少天. 但是我们并不知道要购买多少次,反正是个函数最值问题,直接模拟退火! 看了题解之后,发现购买次数与答案为单峰函数关系,那么可以换成三分法了.. 贪心的话,先预处理出每次要购买的食物(因为有些食物一定不会去买的),然后在保质期内,贪心的全买这种食物即可. /* Telekinetic Forest Guard */ #include <cstdio> #include <

[luogu] P4040 [AHOI2014/JSOI2014]宅男计划(贪心)

P4040 [AHOI2014/JSOI2014]宅男计划 题目背景 自从迷上了拼图,JYY就变成了个彻底的宅男.为了解决温饱问题,JYY不得不依靠叫外卖来维持生计. 题目描述 外卖店一共有N种食物,分别有1到N编号.第i种食物有固定的价钱Pi和保质期Si.第i种食物会在Si天后过期.JYY是不会吃过期食物的. 比如JYY如果今天点了一份保质期为1天的食物,那么JYY必须在今天或者明天把这个食物吃掉,否则这个食物就再也不能吃了.保质期可以为0天,这样这份食物就必须在购买当天吃掉. JYY现在有M

宅男计划:单峰函数三分

Description 自从迷上了拼图,JYY 就变成了个彻底的宅男.为了解决温饱问题,JYY 不得不依靠叫外卖来维持生计. 外卖店一共有n种食物,分别由1到n编号.第i种食物有固定的价钱Pi和保质期Si.第i种食物会在Si天后过期.JYY 是不会吃过期食物的.比如 JYY 如果今天点了一份保质期为0天的食物,那么 JYY 必须在今天或者明天把这个食物吃掉,否则这个食物就再也不能吃了.保质期可以为天,这样这份食物就必须在购买当天吃掉. JYY 现在有M块钱,每一次叫外卖需要额外付给送外卖小哥外送

[AHOI2014/JSOI2014]宅男计划(贪心+三分)

传送门 题意:有N种食物,分别1到N编号.第i种食物有固定的价钱Pi和保质期Si.第i种食物会在Si天后过期(特别地,如果Si=0,表示今天必须吃掉).现在有M元钱,每一次叫外卖需要额外付给外卖小哥外送费F元.外卖小哥可以一次带来任意多份食物.求在满足每天都能吃到至少一顿没过期的外卖的情况下,最多可以活多少天?(突然想到白夜追凶里有一个案件就是讲的外卖小哥对那些每天宅在家中点外卖的人......额,一部挺好看的悬疑剧) 分析:本题需要我们构造贪心条件.我们现在不知道点了多少次外卖,无从下手,但我

BZOJ 3875 Ahoi2014 骑士游戏

3875: [Ahoi2014]骑士游戏 Time Limit: 30 Sec  Memory Limit: 256 MB Description [故事背景] 长期的宅男生活中,JYY又挖掘出了一款RPG游戏.在这个游戏中JYY会 扮演一个英勇的骑士,用他手中的长剑去杀死入侵村庄的怪兽. [问题描述] 在这个游戏中,JYY一共有两种攻击方式,一种是普通攻击,一种是法术攻击.两种攻击方式都会消耗JYY一些体力.采用普通攻击进攻怪兽并不能把怪兽彻底杀死,怪兽的尸体可以变出其他一些新的怪兽,注意一个

bzoj 3876 [Ahoi2014]支线剧情(有上下界的最小费用流)

3876: [Ahoi2014]支线剧情 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 484  Solved: 296[Submit][Status][Discuss] Description [故事背景] 宅男JYY非常喜欢玩RPG游戏,比如仙剑,轩辕剑等等.不过JYY喜欢的并不是战斗场景,而是类似电视剧一般的充满恩怨情仇的剧情.这些游戏往往 都有很多的支线剧情,现在JYY想花费最少的时间看完所有的支线剧情. [问题描述] JYY现在所玩的R

宅男也可变形男-我是如何在11个月零27天减掉80斤的

对我人生态度起到决定性的一个事件 这个事情说起来也是源于98年的一次初中同学聚会,在我的"一切源于一台笔记本"里我提到过,当时我是中专毕业.早早的工作了. 96年11月份开始工作,而当时的初中同学们都还在读高中,一时间觉得自己有收入了可以开销了. 同时我们那个初中和一般学校不一样,因为都是复旦教师的子弟,因此我们从托儿所到幼儿园到小学到初中都是同一批人,感情彼深. 我自己又是一个极念旧情的人,因此一开始有收入后第一件事就是想到的是请以前初中的同学们出来玩,吃饭. 96年开始一年一次,每