【Codeforces Round #398 (Div. 2)】Codeforces 767E Change-free

Student Arseny likes to plan his life for n days ahead. He visits a
canteen every day and he has already decided what he will order in
each of the following n days. Prices in the canteen do not change and
that means Arseny will spend ci rubles during the i-th day. There are
1-ruble coins and 100-ruble notes in circulation. At this moment,
Arseny has m coins and a sufficiently large amount of notes (you can
assume that he has an infinite amount of them). Arseny loves modern
technologies, so he uses his credit card everywhere except the
canteen, but he has to pay in cash in the canteen because it does not
accept cards. Cashier always asks the student to pay change-free.
However, it’s not always possible, but Arseny tries to minimize the
dissatisfaction of the cashier. Cashier’s dissatisfaction for each of
the days is determined by the total amount of notes and coins in the
change. To be precise, if the cashier gives Arseny x notes and coins
on the i-th day, his dissatisfaction for this day equals x·wi. Cashier
always gives change using as little coins and notes as possible, he
always has enough of them to be able to do this. “Caution! Angry
cashier” Arseny wants to pay in such a way that the total
dissatisfaction of the cashier for n days would be as small as
possible. Help him to find out how he needs to pay in each of the n
days! Note that Arseny always has enough money to pay, because he has
an infinite amount of notes. Arseny can use notes and coins he
received in change during any of the following days. Input The first
line contains two integers n and m (1 ≤ n ≤ 105, 0 ≤ m ≤ 109) — the
amount of days Arseny planned his actions for and the amount of coins
he currently has. The second line contains a sequence of integers
c1, c2, …, cn (1 ≤ ci ≤ 105) — the amounts of money in rubles which
Arseny is going to spend for each of the following days. The third
line contains a sequence of integers w1, w2, …, wn (1 ≤ wi ≤ 105) —
the cashier’s dissatisfaction coefficients for each of the following
days. Output In the first line print one integer — minimum possible
total dissatisfaction of the cashier. Then print n lines, the i-th of
then should contain two numbers — the amount of notes and the amount
of coins which Arseny should use to pay in the canteen on the i-th
day. Of course, the total amount of money Arseny gives to the casher
in any of the days should be no less than the amount of money he has
planned to spend. It also shouldn’t exceed 106 rubles: Arseny never
carries large sums of money with him. If there are multiple answers,
print any of them.

稍有常识的人都会看出,需要处理的就是 mod100 之后剩下的部分,是给零钱还是给一张整钱再找。
不妨贪心地能给就给,不能给再找。但是这样显然是不对的。如果碰到不能给的情况,可以尝试修正之前的决策。令人惊喜的是,把任何一个给零钱的决策改成找零钱,都会让零钱增加 100 ,而且这样肯定就够用了。于是可以维护一个堆,里面存修正的花费【也就是 wi(100ai) 】,和当前的花费进行比较。
复杂度 O(nlogn)

#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
#define LL long long
struct opt
{
    int v,num;
    bool operator < (const opt &oo) const
    {
        return v>oo.v;
    }
}o1;
priority_queue<opt> pq;
int a[100010],ans1[100010],ans2[100010],w[100010],n;
int main()
{
    LL m,now=0;
    scanf("%d%I64d",&n,&m);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        ans1[i]=a[i]/100;
        a[i]%=100;
    }
    for (int i=1;i<=n;i++) scanf("%d",&w[i]);
    for (int i=1;i<=n;i++)
    if (a[i])
    {
        if (m>=a[i])
        {
            m-=a[i];
            pq.push((opt){w[i]*(100-a[i]),i});
        }
        else
        {
            if (pq.empty())
            {
                now+=w[i]*(100-a[i]);
                m+=100-a[i];
                ans2[i]=1;
                continue;
            }
            o1=pq.top();
            if (o1.v<w[i]*(100-a[i]))
            {
                pq.pop();
                pq.push((opt){w[i]*(100-a[i]),i});
                now+=o1.v;
                ans2[o1.num]=1;
                m+=100-a[i];
            }
            else
            {
                now+=w[i]*(100-a[i]);
                m+=100-a[i];
                ans2[i]=1;
            }
        }
    }
    printf("%I64d\n",now);
    for (int i=1;i<=n;i++)
        if (ans2[i]) printf("%d 0\n",ans1[i]+1);
        else printf("%d %d\n",ans1[i],a[i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值