noip模拟赛 fateice-shop

题目背景

紫女,韩国歌舞坊(实为刺客组织)紫兰轩之主,千娇百媚,美艳无方。武艺高强且极有谋略胆识,精通奇石药物,冶炼之术及制毒用毒之术独步天下,真实姓名与来历无人知晓,只因总是身着一袭紫衣,所以众人以“紫女”称之。与公子韩非共同创建了“流沙”组织。

题目描述

为了能够获取更多的韩国内部消息,紫女决定收购一批极为罕见的稀世珍宝在紫兰轩进行拍卖,以吸引更多的大人物前来紫兰轩。她准备在m天内购买一些宝物来充实库存。现在,市场上有n种物品,第i种物品的价格为vi,紫女每天最多只能购买xi个。第i天紫女得到wi的钱,她会选择不停购买能买得起的最贵的物品。她想在尽量短的时间内做出决断,所以她需要提前求出每天会购买多少个物品。

由于持有现金非常的危险,每一天买完东西后如果还剩下钱,这些钱就会被丢弃。

输入输出格式

输入格式:

第一行两个整数n,m。接下来n行每行两个整数vi,xi。接下来m行每行一个整数wi。

输出格式:

m行每行一个整数,第i行表示第i天购买的物品数量。

输入输出样例

输入样例#1:
3 3
1 1
2 2
3 3
5
10
15
输出样例#1:
2
4
6

说明

对于20%的数据,n,m<=1000。

对于另外40%的数据,xi=1。

对于100%的数据,n,m<=100000,1<=vi<=10^9,1<=xi<=10000,0<=wi<=10^18。

分析:主要的思想还是二分吧.

      每次要找到<=w的最大的价格,我们可以先对原序列按照价格排个序,然后二分来找.找到以后我们看从这个物品往前买能买到哪,买多少个,这里可以用前缀和+二分解决,如果当前商品买不完就计算一下能买多少个.每次下来w都会减小,我们就不断地缩小右边界不停地二分就可以了.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;

struct node
{
    ll v, x;
}e[100010];

ll n, m;
ll sum[100010], w, sum2[100010],ans;
bool flag = false;

bool cmp(node a, node b)
{
    return a.v < b.v;
}

int erfen(ll maxn)
{
    ll pos = 0, pos2 = 0;
    ll l = 1, r = maxn;
    while (l <= r)
    {
        ll mid = (l + r) >> 1;
        if (e[mid].v <= w)
        {
            pos = mid;
            l = mid + 1;
        }
        else
            r = mid - 1;
    }
    if (!pos)
    {
        flag = 1;
        return 0;
    }
    l = 1, r = pos;
    pos2 = pos;
    while (l <= r)
    {
        ll mid = (l + r) >> 1;
        if (sum[pos] - sum[mid] <= w)
        {
            pos2 = mid;
            r = mid - 1;
        }
        else
            l = mid + 1;
    }
    w -= sum[pos] - sum[pos2];
    ans += sum2[pos] - sum2[pos2];
    ll use = e[pos2].x;
    
    while (w >= e[pos2].v && use)
    {
        use--;
        w -= e[pos2].v;
        ans++;
    }
    if (use == 0)
        return pos2 - 1;
    else
        return pos2;
}

int main()
{
    scanf("%lld%lld", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%lld%lld", &e[i].v, &e[i].x);
    sort(e + 1, e + n + 1, cmp);
    for (int i = 1; i <= n; i++)
    {
        sum[i] = sum[i - 1] + e[i].v * e[i].x;
        sum2[i] = sum2[i - 1] + e[i].x;
    }
    while (m--)
    {
        flag = 0;
        scanf("%lld", &w);
        ans = 0;
        int t = erfen(n);
        while (!flag && w >= e[1].v && t > 0)
            t = erfen(t);
        printf("%lld
", ans);
    }

    return 0;
}
原文地址:https://www.cnblogs.com/zbtrs/p/7670688.html