【bzoj2832】宅男小C

Description

众所周知,小C是个宅男,所以他的每天的食物要靠外卖来解决。小C现在有M元钱,他想知道这些钱他最多可以吃多少天。

餐厅提供N种食物,每种食物有两个属性,单价Pi和保质期Si,表示小C需要花Pi元才能买到足够一天吃的这种食物,并且需要在送到Si天内吃完,否则食物会变质,就不能吃了,若Si为0则意味着必须在送到当天吃完。另外,每次送餐需要额外F元送餐费。
Input

每个测试点包含多组测试数据;
每个测试数据第一行三个整数M,F,N,如题目描述中所述;
以下N行,每行两个整数,分别表示Pi和Si。
Output

对于每个测试数据输出一行,表示最多可以吃的天数。
Sample Input

32 5 2

5 0

10 2

10 10 1

10 10

10 1 1

1 5

Sample Output

3

0

8

HINT

【数据规模及约定】

对于40%的数据,M,Si <= 2*10^6;

对于100%的数据,M, Si<= 10^18,1 ≤ T ≤ 50,1 ≤ F ≤ M,1 ≤ N ≤ 200,1 ≤ Pi ≤ M。

题解
首先删去没用的食品(保质期短还贵的),得到保质期短的便宜,保质期长的贵。
三分购买几次,贪心地从保质期短的开始买。

代码

#include<bits/stdc++.h>
#define ll long long
#define inf 1000000000
#define pa pair<ll,ll>
using namespace std;
const int mod=1000000007;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct node{ll p,s;}a[205],b[205];
ll n,f,m;
pa ans;
bool cmp(node a,node b)
{
    return (a.s==b.s)?a.p<b.p:a.s<b.s;
}
pa judge(ll mid)
{
    ll rest=m-f*mid,day=0,now=0;
    for (int i=1;i<=n;i++)
    {
        if (b[i].s>=day)
        {
            ll j=min(rest/b[i].p/mid,b[i].s-day+1);
            day+=j;now+=mid*j;rest-=b[i].p*j*mid;
        }
        if (b[i].s>=day)
        {
            ll j=min(rest/b[i].p,mid);
            now+=j;day++;rest-=b[i].p*j;
        }
    }
    return make_pair(now,rest);
}
int main()
{
    while (scanf("%lld%lld%lld",&m,&f,&n)!=EOF)
    {
        for (int i=1;i<=n;i++) scanf("%lld%lld",&a[i].p,&a[i].s);
        sort(a+1,a+n+1,cmp);int _n=0;
        for (int i=1;i<=n;i++)
        {
            while (_n!=0&&a[i].p<=b[_n].p) _n--;
            b[++_n]=a[i];
        }
        n=_n;
        ll l=1,r=m/(f+b[1].p);ans=make_pair(0,0);
        while (l<=r)
        {
            ll m1=l+(r-l)/3,m2=r-(r-l)/3;pa s1,s2;
            if ((s1=judge(m1))>(s2=judge(m2)))
            {
                ans=max(ans,s1);
                r=m2-1;
            }
            else
            {
                ans=max(ans,s2);
                l=m1+1;
            }
        }
        printf("%lld\n",ans.first);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值