这题虽然我比赛的时候没过,但是我后来补的时候自己还是写出来了;好开心嘻嘻;
比赛的时候我把题理解错了QAQ,我以为hi表示一个block的高度QAQ(该打脸了QAQ);结果后来补题才发现,所有block高度是一样的;
题意:给你n列,并且ai(1<=i<=n)表示每一列所拥有的block个数,同时你有一个bag,它无限大;你可以有以下操作:
1.如果你现在正在第i column上面,那么你可以从第i column的顶端取任意多个你脚下的block放进口袋里面;
2.如果你的口袋里面有block那么你就可以拿出任意多个block出来放在你的脚下让第i column变高(注意这里口袋必须满足是非空才能取block);
3.如果满足|hi-hi+1|<=k才能走到下一column上面,而且这是唯一的前进方式;
好了只要理解了这三点思路应该就有了;
直接扫一遍;
在扫的时候:
1.a[i]>=a[i+1]的时候,我可以把a[i]在满足能前进的情况下把a[i]中block尽可能放进口袋,这样我就会有多的block以防以后遇见太低的时候我就能从口袋拿出来踮高了,嘻嘻;这里就是贪心了;注意在放进口袋的时候,需要注意k的大小问题:
可以知道我把a[i]削掉一部分后和a[i+1]相等,但是k就有两种情况,因为|a[i]-a[i+1]|<=k所以我可以知道在满足这个等式时,a[i]可以取到比a[i+1]还要小的时候,只需要用削掉的 a[i]部分减去k就可以了,然后把k补充进我的口袋;这里就是贪心:但是注意了如果b这一坨不够减,那么只需要把b补充进口袋就行了;因为a[i]=0时也满足前进的条件(|a[i]-a[i+1]|<=k);(这里可以用笔算一算去理解就好了);
其实就需要注意在补充的时候尽量补充进口袋;
2.如果a[i]<a[i+1]了;那么它要么前进,要么需要从口袋拿出block来垫高:如果能前进那么我就同理的尽可能拿掉一些block在保证能前进的情况下;如果不能前进那么我就需要看是不是能够从口袋拿出来补充给我现在站在的这column让我能够前进(尽量补充少的block这样我能为后面前进提供更大的机会);
所以问题就解决了:
其实主要是注意在补充和削掉的时候和k的数量关系和每走一步尽可能的拿block进口袋,在不能前进的时候尽可能的补充少的block,只要清楚了这个关系就可以过了:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//ll gcd(ll a,ll b){
// return b?gcd(b,a%b):a;
//}
int main(){
ll T,a[200];
scanf("%lld",&T);
ll n,m,k;
while(T--){
memset(a,0,sizeof(a));
scanf("%lld %lld %lld",&n,&m,&k);
for(int i=0;i<n;i++)scanf("%lld",a+i);
int f1=0;
for(int i=0;i<n-1;i++){
if(a[i]>=a[i+1]){//这里就是上面的第一种情况
int t=a[i]-a[i+1];
a[i]-=t;
if(a[i]-k>=0){//能够在满足前进的时候尽可能多的 放block进口袋
m+=k+t;
a[i]-=k;
}else{
m+=t+a[i];
a[i]=0;
}
continue;
}else{
if(a[i+1]-a[i]<=k){//在本身不需要改变就能跳过的时候
int t=a[i+1]-k;
if(t>=0){//能够在满足前进的时候尽可能对的 放block进口袋
m+=a[i]-t;
}else{
m+=a[i];
a[i]=0;
}
continue;
}
else{//在需要补充才能跳过的时候
int t=a[i+1]-k-a[i];//这里需要用笔算一下才知道(注意这里是a[i+1]>a[i])
if(m-t>=0){//如果能补充
m-=t;
a[i]+=t;continue;
}else{
puts("NO");f1=1;break;
}
}
}
}
if(!f1)puts("YES");
}
return 0;
}