修路

且-行發表於2020-12-27

P5019 [NOIP2018 提高組] 鋪設道路 題解

返回題目
由於雨水沖刷,長度為N的路面下陷。勤勞的養路工人使用機器恢復路面,機器每天只能對一段路面[L,R]之間的區域進行1個單位深度的填充修補,道路的
路況用下陷的深度表示。請程式設計輸出修好這條路至少需要的天數。

【輸入形式】

第一行一個整數N;

第二行N個空格隔開的整數,表示路面的下陷程度。
【輸出形式】

一個整數,表示所用的天數。
【樣例輸入】

6

1 3 2 4 5 3
【樣例輸出】

6
【樣例說明】

6天修補[1,6], [2,6], [2,2], [4,6], [4,5], [5,5]路段即可。

【評分標準】

0<N<100000;

輸出正確的答案。
1

它就是一個貪心。
題目裡給的樣例是432535;

可以選擇一個區間進行“填坑”操作;

所以我們的貪心策略是:

若a[i]>a[i-1],計數器sum+=a[i]-a[i-1];
那麼為什麼這樣貪心是對的呢?

貪心證明
假設現在有一個坑,但旁邊又有一個坑。

你肯定會選擇把兩個同時減1;

那麼小的坑肯定會被大的坑“帶著”填掉。

大的坑也會減少a[i]-a[i-1]的深度,可以說是“免費的”;

所以這樣貪心是對的;

程式碼
#include<bits/stdc++.h>
using namespace std;
int n,a[100005];
long long ans=0;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)     cin>>a[i];
	for(int i=2;i<=n;i++)     if(a[i]>a[i-1]) ans+=a[i]-a[i-1];
	cout<<ans+a[1];
	return 0;
}
記得要加上a[1],或者在前面填一個0; (這是本蒟蒻第一次寫題解,支援一下哦。)

2

#include <cstdio>
#include <algorithm>
using namespace std;
int a[100010];
int main()
{
	int n;
	scanf("%d",&n);
	int minn=0x3f3f3f3f;
	for(int i=1;i<=n;++i)
	{
		scanf("%d",&a[i]);
		if(a[i]<minn)minn=a[i];
	}
	for(int i=1;i<=n;++i)
		a[i]-=minn;
	long long sum=minn;
	int k=0;
	for(int i=1;;++i)//未知次操作
	{
		if(!a[k])
		{
			k++;
			if(k==n+1)break;
		}//遍歷非0段
		int minx=a[k];
		for(int j=k;j<=n;++j)
		{
			if(!a[j])break;
			if(a[j]<minx)minx=a[j];
		}
		for(int j=k;j<=n;++j)
		{
			if(!a[j])break;
			a[j]-=minx;
		}//處理
		sum+=minx;
	}
	printf("%lld\n",sum);
	return 0;
}