1443D Extreme Subtraction
题意:对于一个长度为n的数组有两种操作,前k个数减一,后k个数减一,这两种操作可执行任意多次,问是否能将数组变为全零
思路:首先的是暴力模拟,也可以叫做贪心吧,我们可以这样想尽可能的让左边减去更多,同时如果左边的减不掉那么多的话,用d来存储我们向右边借的数,如果a[i]-d小于零的话就意味着不能全变为零,反之,如果a[i]大于零且大于mm(mm为左边能提供的最大减数),那么这个时候就需要右边的帮忙,d要加上他们的差值,如果a[i]小于mm,那么就更新mm的值,因为之后左边能提供的最大减数变为了a[i]。
另外一种更为巧妙的是差分,首先获得该数组a的差分数组s,那么对于操作一,对数组s的操作变为s[0]–,s[k+1]++,对于操作二,对数组的操作变为s[k]–, s[n]++, (我的数组下标是0到n-1,1到n也行),那么就意味着现在能进行的操作是对这个数组大于零的数都能变为零,而小于零的数要进行判断如果所有小于零的数的和的绝对值小于等于s[0],即可以变为全零反之则不能。
代码如下:
差分
int a[maxn];
inline void cf(){
int t=read();
while(t--){
int n = read(), res = 0;
for(int i = 0; i < n; i++){
a[i] = read();
if(i&&a[i]<a[i-1]) res += a[i-1]-a[i];
}
if(res<=a[0]) printf("YES\n");
else printf("NO\n");
}
return ;
}
signed main(){
cf();
return 0;
}
模拟部分代码如下:
int n = read();
for(int i = 0; i < n; i++) a[i] = read();
int flag = 1, d = 0, mm = a[0];
for(int i = 0; i < n; i++){
a[i] -= d;
if(a[i]<0){
flag = 0;break;
}
if(a[i]>mm){
d += a[i]-mm;
}else mm = a[i];
}
if(flag) printf("YES\n");
else printf("NO\n");