Helping the Nature(思维,差分,构造)

题目链接:This is link

题目大意:

给你一个长度为 n n n 的序列 a a a,每次可以进行一下三种操作的任意一种

  • 选择 i i i,使得 a 1 , a 2 , a 3 , … , a i a_1,a_2,a_3,…,a_i a1,a2,a3,,ai 减 1.
  • 选择 i i i,使得 a i , a i + 1 , a i + 2 , … , a n a_i,a_{i+1},a_{i+2},…,a_n ai,ai+1,ai+2,,an 减 1.
  • 将序列中的每个数加 1.

求将序列 a a a中的每个元素变为1的最小操作次数。

解题思路:

通过操作1和操作2我们可知它是对序列的左右区间是有影响的,而操作3是对整个序列是有影响的。并且我们发现当序列是单调递增的时候,我们可以很容易的求出来操作次数。

例如: 5 5 6 8 9 将此序列全部变成0的最小操作次数为9次,即只选择操作二即可,选择的下标为 :1,1,1,1,1,3,4,4,5。所以我们很容易发现当序列是单调递增且 a 1 ≥ 0 a_1 ≥ 0 a10的时候,操作次数为 a n a_n an. 所以我们不妨去构造这样的一个序列,进而求取最小操作次数。

那么该怎么去构造呢?我们可以从后到前枚举每一个元素,如果当前元素大于后面相邻元素,我们可以通过操作一 ( a i − a i + 1 a_i -a_{i+1} aiai+1)次来让当前元素等于后面相邻元素,直至枚举完第一个元素。
举个例子:4 -4 4 -4

  • 首先a[3] > a[4] ,我们通过操作一 ( a[3] - a[4] )次使得序列变成: -4 -12 -4 -4
  • 然后a[2] < a[3] ,跳过即可
  • 又因为a[1] > a[2] ,我们通过操作一( a[1] - a[2] )次使得序列变成:-12 -12 -4 -4
  • 此时我们已经使得序列成为了一个单调递增的序列,但是我们发现 a 1 a_1 a1是小于 0 0 0的,所以我们需要通过操作三12次使得序列成为:0 0 8 8 ,这样才构造出来了我么所需要的序列。

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
int a[N];
int main()
{
	int t; cin >> t;
	while (t--)
	{
		int n; cin >> n;
		for (int i = 1; i <= n; i++)
		{
			cin >> a[i];
		}
		ll ans = 0;
		for (int i = n - 1; i >= 1; i--)
		{
			if (a[i] > a[i + 1]) ans += a[i] - a[i + 1];
		}
		if (a[1] - ans >= 0) cout << ans + a[n] << endl;
		else cout << ans + (ans - a[1]) * 2 + a[n] << endl;
	}
	return 0;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值