​传送门​

题意

给定一个数组,每次可以把一个前缀的数全部减一,或者把一个后缀全部减一

问最后有没有可能让所有数都变成 0 0 0


代劳们的神仙差分思路

考虑差分数组 a n s [ i ] ans[i] ans[i].如果所有数变成零,那么最后 a n s ans ans一定也是零

对于操作一,就是 a n s [ 1 ] − − , a n s [ i + 1 ] + + ans[1]- -,ans[i+1]++ ans[1]−−,ans[i+1]++

对于操作二,就是 a n s [ i ] − − , a n s [ n + 1 ] + + ans[i]--,ans[n+1]++ ans[i]−−,ans[n+1]++

那么观察到 a n s [ 1 ] ans[1] ans[1]只会一直减小

而后续如果想让某个 a n s [ i ] ans[i] ans[i]从负数变成零必然要用操作一

后续如果要让某个 a n s [ i ] ans[i] ans[i]从正数变成零用操作二就可以了

而且操作二不管让 a n s [ n + 1 ] ans[n+1] ans[n+1]变成多少都无所谓

因为只要保证 [ 1 , n ] [1,n] [1,n]的差分数组为零都是相同的数,那肯定能变成全是零

所以只需要关心 a n s [ 1 ] ans[1] ans[1]是不是足以让后面的所有负的 a n s [ i ] ans[i] ans[i]变成零

#include "iostream"
using namespace std;
const int maxn = 2e6+10;
int a[maxn],n,ans[maxn];
int main()
{
int t; cin >> t;
while( t-- )
{
cin >> n;
for(int i=1;i<=n;i++) cin >> a[i], ans[i] = a[i]-a[i-1];
for(int i=2;i<=n;i++)
if( ans[i]<0 ) ans[1]+=ans[i];
if( ans[1]>=0 ) cout << "YES\n";
else cout << "NO\n";
}
}

我的做法贪心

宗旨是先只考虑操作一如何操作最优

只要通过操作一把序列变成不递减,说明可以只通过操作二来完成.

比如11 7 9

第一个数肯定操作了 11 11 11次,然后到第二个数,现在衰减到 7 7 7次,但是都变成了零

但是第三个数怎么办??已经不能让它等于0了

贪心策略是让它在大于等于前面数字的前提下尽量小

这个应该很好理解,大于前面的话无法通过操作二来消除

尽量小则是让操作二更容易消除

基 于 这 个 贪 心 法 则 , 甚 至 可 以 构 造 出 最 优 的 操 作 顺 序 \color{Red}基于这个贪心法则,甚至可以构造出最优的操作顺序 基于这个贪心法则,甚至可以构造出最优的操作顺序

因为这样操作最后序列变成不递减的了,可以只通过操作二来实现.

#include "iostream"
using namespace std;
const int maxn = 2e6+10;
int a[maxn],n;
int main()
{
int t; cin >> t;
while( t-- )
{
cin >> n;
for(int i=1;i<=n;i++) cin >> a[i];
int ci = a[1], flag = 0;//初始操作次数是a[1]
a[1] = 0;
for(int i=2;i<=n;i++)
{
if( a[i]<a[i-1] ) flag = 1;
else ci = min( ci,a[i]-a[i-1] ),a[i]-=ci;
}
if( flag ) cout << "NO\n";
else cout << "YES\n";
}
}