写了一下午代码越发地觉得自己是个傻逼
这和这篇博客并没有什么关系只是单纯地感叹一下
这是一道2018、2013以及USACO都考过的题目,非常地经典,这里提供递归和贪心的两种题解。
1、递归
题目很简单,就是填坑嘛,能一起填的就一起填呗,这样省事,然后依次找可以一起填的子区间填就是了,发现处理过程非常相似就想到递归咯。
这道题如果用暴力的话会超时,这里把能一起填的直接加就会简便一些,时间复杂度大致O(nlogn)
具体细节见代码:
#include <cstdio>
#include <iostream>
using namespace std;
int n, ans;
int a[100005];
int findminn(int l, int r)//找出从left到right中的最小值
{
int minn = 2147483647;
for(int i = l; i <= r; i ++)
{
if(a[i] < minn) minn = a[i];
}
return minn;
}
void printline()//实际代码中没啥用,当初为了debug写的
{
for(int i = 1; i <= n; i ++) printf("%d ", a[i]);
printf("\n");
}
void search(int l, int r)
{
int minn, flag1, flag2;
if(l == r)//递归结束条件
{
ans += a[l];
return ;
}
minn = findminn(l , r);
ans += minn;
for(int i = l; i <= r; i ++) a[i] -= minn;
flag1 = l;
while(flag1 <= r)
{
while(!a[flag1] && flag1 <= r) flag1 ++;
flag2 = flag1;
while(a[flag2] && flag2 <= r) flag2 ++;
flag2 --;//注意这里要减1才能获取目标区间
if(flag2 <= r && flag1 <= r) search(flag1, flag2);
flag1 = flag2 + 1;//为找下一个区间做准备,不加这个会死循环
}
return ;
}
int main()//main函数不超10行,我们老师教我们的
{
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
search(1, n);
printf("%d\n", ans);
return 0;
}
2、贪心
刚刚的想法是我看了题后自己尝试的,看了大佬的题解才发现贪心的真正牛逼之处:
如果大坑旁边还有个小坑,填大坑的时候就顺便把小坑也填了
(数组可能比较大我就开vector了)
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
int n, ans;
int main()//别问,问就是main函数不超过10行
{
scanf("%d", &n);
vector<int> a(n + 5, 0);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
for(int i = 2; i <= n; i ++)
{
if(a[i] > a[i-1]) ans += a[i] - a[i-1];
}
printf("%d\n", ans + a[1]);
return 0;
}