求清洁木板的最少次数

Description

Time Limit: 1sec Memory Limit:256MB

某人想检验最近新研发的清洁工具的效果,便找来一块布满污渍的长木板。长木板上的污渍厚度不一。

清洁工具每次的工作原理是这样的:其矩形探头可以伸缩任意长度,然后选取木板上的一段区间进行去污,之后这段区间所有的污渍厚度减一。注意不能向木板中无污渍的地方去污,否则会导致木板损坏。问最少需要多少次才能清洁木板

或者我们可以将其抽象成这样的模型:给出木板长度n以及每段污渍的厚度a1,a2,…,an,每次操作可以选取区间 [l,r] (1<=l<=r<=n,ai>0,l<=i<=r),之后将这个区间上的所有数都减一,但需保证这段区间的数操作之前均大于0。问使得a1,a2,…,an均为0最少需要多少次操作。

Input

第一行一个正整数T(<=20),表示数据的个数

接下来T组数据,第一行为木板的长度n(<=100)

接下来n个非负整数ai(<=100),表示距离为i处的污渍厚度

Output

每组数据输出一行,一个数,表示最少需要清洁的次数

Sample Input

2
5
2 4 1 2 3
2
3 4

Sample Output

6
4

Hint

第一组数据解释:第一次清理[1,5],剩下1,3,0,1,2

第二次清理[1,2],第三次与第四次清理[2,2],第五次清理[4,5],最后一次清理[5,5]。

一共六次,可以证明这是最少的次数。

分析

可以知道木板的污渍厚度其实是一个波峰图,我们要找的就是每个波峰,以及处在下降和上升之间的转折点。因为规律为:最少的清洁次数为波峰的和减去转折点值之和所得的差。有兴趣的同学可以自己画画图多试几遍。

		for(int i = 0;i < n;i++){
			if(arr[i] >= maxNum[index]){//找升序 
				maxNum[index] = arr[i];
			}
			else{
				while(arr[i+1] <= arr[i]&& i+1 < n){//找降序 
					i++;
				}
				right[index] = arr[i];//找到分界 
				index++;
				maxNum[index] = arr[i];
			}
		}

要特别注意的是,最后一组的波峰有可能刚好是最后一个数据,所以我们要判断,并且最后总和那里也要处理好。

		if(right[index] == 0){
			right[index] = arr[n-1];//最后一个数字为最后一个组合的最大数 
		}

		int sum = 0;
		for(int i = 1;i < index;i++){
		    sum += maxNum[i];
		    sum -= right[i];
		} 
		sum += maxNum[index];

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;

int n;

int main(){
	int T;
	cin>>T;
	for(int t = 0;t < T;t++){
		cin>>n;
		int arr[n];
		//<int> vec;
		for(int i = 0;i < n;i++){
			cin>>arr[i];
			//arr.push_back();
		}
		
		int maxNum[n],right[n+1];
		memset(maxNum,0,sizeof(maxNum));
		memset(right,0,sizeof(right));
		right[0] = 0;
 
		int index = 1;
		maxNum[index] = arr[0];
		for(int i = 0;i < n;i++){
			if(arr[i] >= maxNum[index]){//找升序 
				maxNum[index] = arr[i];
			}
			else{
				while(arr[i+1] <= arr[i]&& i+1 < n){//找降序 
					i++;
				}
				right[index] = arr[i];//找到分界 
				index++;
				maxNum[index] = arr[i];
			}
		}
		if(right[index] == 0){
			right[index] = arr[n-1];//最后一个数字为最后一个组合的最大数 
		}

		int sum = 0;
		for(int i = 1;i < index;i++){
		    sum += maxNum[i];
		    sum -= right[i];
		} 
		sum += maxNum[index];
		
		cout<<sum<<endl;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值