Educational Codeforces Round 33 D. Credit Card

来源:互联网 发布:vb6.0软件发展 编辑:程序博客网 时间:2024/05/20 07:36

原题:
Recenlty Luba got a credit card and started to use it. Let’s consider n consecutive days Luba uses the card.

She starts with 0 money on her account.

In the evening of i-th day a transaction ai occurs. If ai > 0, then ai bourles are deposited to Luba’s account. If ai < 0, then ai bourles are withdrawn. And if ai = 0, then the amount of money on Luba’s account is checked.

In the morning of any of n days Luba can go to the bank and deposit any positive integer amount of burles to her account. But there is a limitation: the amount of money on the account can never exceed d.

It can happen that the amount of money goes greater than d by some transaction in the evening. In this case answer will be «-1».

Luba must not exceed this limit, and also she wants that every day her account is checked (the days when ai = 0) the amount of money on her account is non-negative. It takes a lot of time to go to the bank, so Luba wants to know the minimum number of days she needs to deposit some money to her account (if it is possible to meet all the requirements). Help her!

Input
The first line contains two integers n, d (1 ≤ n ≤ 105, 1 ≤ d ≤ 109) —the number of days and the money limitation.

The second line contains n integer numbers a1, a2, … an ( - 104 ≤ ai ≤ 104), where ai represents the transaction in i-th day.

Output
Print -1 if Luba cannot deposit the money to her account in such a way that the requirements are met. Otherwise print the minimum number of days Luba has to deposit money.

Examples
input
5 10
-1 5 0 -5 3
output
0
input
3 4
-10 0 20
output
-1
input
5 10
-5 0 10 -11 0
output
2

中文:

你有你个账户,可以存钱和取钱,给你两个数n和d。分别表示有n次操作,和账户中钱数上限。
然后给你n个数,正数表示存钱,负数表示取钱,0表示查账。存款的总额不能超过d,每次查账的时候要求账户中的钱数必须大于0。每一天都可以在账户里面加钱,现在问最少加多少次钱可以保证账户查账时不出现透支。
如果每天固定的存取款钱数超过上限,输出-1。

#include<bits/stdc++.h>using namespace std;int res[100001];int n,d;int main(){    ios::sync_with_stdio(false);    while(cin>>n>>d)    {        for(int i=1;i<=n;i++)            cin>>res[i];        int l,r,cnt;        l=r=cnt=0;        int flag=1;        for(int i=1;i<=n;i++)        {            if(res[i]==0)            {                if(r<0)                {                    cnt++;                    r=d;                }                if(l<0)                    l=0;            }            else            {                l+=res[i];                r+=res[i];                if(r>d)                    r=d;                if(l>d)                {                    flag=0;                    break;                }            }        }        if(flag)            cout<<cnt<<endl;        else            cout<<-1<<endl;    }    return 0;}

解答:

由于每次都是在输入为0的情况下检查账户是否欠款,而且存钱的数目无限大。所以,可以考虑每次在查账的时候存钱,这里要满足三个条件。每次存钱既要满足把欠的钱换上;满足在以后的操作序列中,账户上限不超过d;尽量的多存才能使后面存钱次数最少。

例如
5 10
-5 0 10 -11 0

第一个条件,把欠的钱还上,由于不限制打钱金额,所以直接变为正数就算是一次存钱。

第二个条件比较重要,当前存钱的范围是多少才能使得后面的操作不会出现账户中的钱数不超过d?
既然涉及到后续问题,那么肯定要考虑到后面的数据并对后面的数据进行处理。我在考虑此问题时犯了个严重的错误,我把所有数据按照0这个操作分开考虑,分别从后往前计算累加和,结果越想越麻烦。

官方题解中的解释是,如果在某次进行查账的时候,要保存一个数值suf[i],这个值记录的是从后向前到i时后面会出现的账户金额最高是多少!那么,当前要塞入的钱数就是d-suf[i]。
首先,计算从头到尾计算累加和pre[i],该步骤保留的是在从头至此的操作当中,账户中的余额是多少。
然后,从后向前,计算suf[i],每次保留suf[i]=max(maxsuf[i + 1], pre[i]),记录账户中从后到i点钟账户出现最大的余额是多少。
例如此篇文章

在网上搜索题解的时候,发现另外一种解决方法。每次维护一个区间,分别是不存钱时账户中剩余的最大余额l,和去银行存钱后剩余的最大余额r。
每次计算的时候,如果发现l大于d,说明原来的操作序列不合理,跳出。
每次检查的时候,如果发现r小于0,此时,那么直接把账户余额改为d,如果发现l小于0,那么l改为0,并增强一次存款记录。
可以这样操作的原因是,如果根据后面的序列得出当前存钱应该存取某个数值可以使得后面的某次余额正好为上限,那么不需要考虑当前存多少钱,只需要加满钱即可。不存款时剩余的最大余额一定是最起码保证在查账时数值非负。

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手机电池鼓包还能用吗 充电宝鼓包还能用吗 菠萝包破解版能用吗 用养森瘦瘦包为什么不能喝水 电池鼓包了还能用吗 汽车竹炭包能用多久 牙龈脓包用盐能自愈吗 擦脚布 6个脚布衣柜组装图 打捆机包膜机 包膜机价格 青储包膜机 包臀连衣裙图片 夏季修身包臀连衣裙 紧身包臀连衣裙 气质修身包臀连衣裙 修身包臀连衣裙 无袖包臀连衣裙 包臀图片 街拍包臀短裙图片 性感包臀 包臀短裙图片 包臀裤 包臀长裙 包臀裙子 包臀热舞 黑色包臀长裙怎么搭配 臀包 街拍紧身包臀 包臀紧身裙 连衣包臀裙 性感包臀裙 打底裙包臀 包臀裙吧 黑色包臀裙 超短包臀裙图片 包臀裙女教师 妈妈的包臀裙 包臀裙ol 制服包臀裙 包臀裙 短裙