codeforces893D Credit Card

对着AC代码苦思冥想两个小时终于顿悟…真是神奇的做法。
大概算奥妙重重的贪心?
我给它起名叫:区间贪心!(雾)


惯例题意。一个人在银行里有一张信用卡。
晚上会有钱进来,不过:
1)如果送进来正数元,那就很棒。但是如果超过某个上限k,这个人就会被双规。
2)如果送进来0元,那就是在传递信号,第二天会有人查账户,要求账户不透支。
3)如果送进来负的,那就很惨。而且,信用卡是有可能透支的。
为了拯救自己的账户,这个人借了很多钱,并且可以在任意一天存入。这里的问题是,他最少存多少次,就可以应付过每一次检查?
如果会被双规,输出-1


不妨设表示晚上送钱的数组为 a
首先,我们会发现,在ai=0时处理即可。这是因为,在每一天的处理都可以等价到那一天。
考虑一下,可以将两次检查之间的结果作为一个区间。
然后不妨思考一下,假设现在刚刚检查过一次,存钱之后的剩余钱范围设为 [low,top] ,显然初始时为 [0,k] ,因为可以存0~k元。然后,我们对这个区间进行这些操作( ai0 ):
每扫到一个数先变成 [low+ai,top+ai] 。如果新的 top>k ,由于存钱不可能超过 k ,那么最大值不变;而如果low>k,表示最少需要存的钱也会比 k 大,GG。
如果遇到了一次新的检查,有两种情况:一种是上次最多存的钱已经被挥霍完了,那么又该存新的了;一种是还没有被挥霍完,可以到下一个区间去挥霍。对于前者,直接++ans然后初始化一下 low top ;对于后者,如果 low<0 ,就让 low=0 ,因为不能存0元以下。
大概可以看做下图:

这一贪心思想比较奇特,是对区间贪心的。至于题解给的…恕在下没有看懂…


#include <iostream>
#include <cstdio>
using namespace std;
int low, top, n, k, ans;
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0); 
    cin>>n>>k;
    low = 0; top = 0;
    int tmp;
    for(int i = 1; i <= n; ++i) {
        cin>>tmp;
        if(tmp) {
            low += tmp, top += tmp;
            if(low > k) return puts("-1"), 0;
            if(top > k) top = k;
        } else {
            if(top < 0){++ans, top = k, low = 0;}
            else low = max(low, 0);
        }
    }
    cout<<ans<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值