题目传送门
一、贪心法
题目里给的样例是\(4,3,2,5,3,5\),可以选择一个区间进行“填坑”操作;我们的贪心策略是:
若\(a[i]>a[i-1]\),计数器\(sum+=a[i]-a[i-1]\);
贪心证明
假设现在有一个坑,但旁边又有一个坑。你肯定会选择把两个同时填充,都减\(1\);那么小的坑肯定会被大的坑“带着”填掉。大的坑也会减少\(a[i]-a[i-1]\)的深度,可以说是“免费的”;所以这样贪心是对的。
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N = 1000010; int a[N]; LL ans; int n; int main() { cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= n; i++) if (a[i] > a[i - 1]) ans += a[i] - a[i - 1]; cout << ans; return 0; }
2、递推法
用\(f[i]\)表示前\(i\)个坑所铺设的最少次数。
那么要做的只需比较一下当前的\(a[i]\)就是坑的深度)和\(a[i-1]\),分两种情况:
1、如果\(a[i]<=a[i-1]\),那么在填\(a[i-1]\)时就可以顺便把\(a[i]\)填上,这样显然更优,所以\(f[i]=f[i-1]\);
2、如果\(a[i]>a[i-1]\),那么在填\(a[i-1]\)时肯定要尽量把\(a[i]\)一块填上一部分(\(a[i-1]\)),\(a[i]\)剩余的就单独填。
所以,\(f[i]=f[i-1]+(a[i]-a[i-1])\)。
初始化\(f[1]=a[1]\),向后推就行了,复杂度大概是\(O(n)\)。
#include <bits/stdc++.h> using namespace std; const int N = 1000010; //递推法 int n, a[N]; int f[N]; //代表前i个区域被填充好的最少次数.套路,满满的套路 int main() { cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; //递推出口,第一个有多大的坑,不能指望别人,都要靠自己来完成~ f[1] = a[1]; //从第2个开始进行递推 for (int i = 2; i <= n; i++) { //递推式:见题解的分析过程 if (a[i] <= a[i - 1]) f[i] = f[i - 1]; else f[i] = f[i - 1] + (a[i] - a[i - 1]); } //输出大吉 cout << f[n] << endl; return 0; }