1442AA. Extreme Subtraction(贪心思维或差分)

传送门

题意

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

问最后有没有可能让所有数都变成 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";
	}
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值