对着AC代码苦思冥想两个小时终于顿悟…真是神奇的做法。
大概算奥妙重重的贪心?
我给它起名叫:区间贪心!(雾)
惯例题意。一个人在银行里有一张信用卡。
晚上会有钱进来,不过:
1)如果送进来正数元,那就很棒。但是如果超过某个上限k,这个人就会被双规。
2)如果送进来0元,那就是在传递信号,第二天会有人查账户,要求账户不透支。
3)如果送进来负的,那就很惨。而且,信用卡是有可能透支的。
为了拯救自己的账户,这个人借了很多钱,并且可以在任意一天存入。这里的问题是,他最少存多少次,就可以应付过每一次检查?
如果会被双规,输出-1
不妨设表示晚上送钱的数组为
a
首先,我们会发现,在
考虑一下,可以将两次检查之间的结果作为一个区间。
然后不妨思考一下,假设现在刚刚检查过一次,存钱之后的剩余钱范围设为
[low,top]
,显然初始时为
[0,k]
,因为可以存0~k元。然后,我们对这个区间进行这些操作(
ai≠0
):
每扫到一个数先变成
[low+ai,top+ai]
。如果新的
top>k
,由于存钱不可能超过
k
,那么最大值不变;而如果
如果遇到了一次新的检查,有两种情况:一种是上次最多存的钱已经被挥霍完了,那么又该存新的了;一种是还没有被挥霍完,可以到下一个区间去挥霍。对于前者,直接
大概可以看做下图:
这一贪心思想比较奇特,是对区间贪心的。至于题解给的…恕在下没有看懂…
#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;
}