分糖果问题
题目描述
一群孩子做游戏,现在请你根据游戏得分来发糖果,要求如下:
-
每个孩子不管得分多少,起码分到一个糖果。
-
任意两个相邻的孩子之间,得分较多的孩子必须拿多一些糖果。(若相同则无此限制)
给定一个数组arr代表得分数组,请返回最少需要多少糖果。
输入描述:
第一行一个整数N表示数组大小
接下来一行N个整数表示数组内的元素
输出描述:
输出一个整数表示答案
示例1
输入
3
1 2 2
输出
4
说明
最优分配方案为1, 2, 1
备注:
1
⩽
N
⩽
1
0
5
1 \leqslant N \leqslant 10^5
1⩽N⩽105
0
⩽
a
i
⩽
1
0
5
0 \leqslant a_i \leqslant 10^5
0⩽ai⩽105
题解:
正反两次 dp 即可。
-
正向 dp
- 若 a[i] > a[i - 1],则 f[i] = f[i - 1] + 1
- 若 a[i] <= a[i - 1] ,则 f[i] = 1
-
反向 dp
- 若 a[i] > a[i - 1] && f[i] <= f[i - 1],则 f[i] = f[i - 1] + 1
- 否则的话,f[i] 不动
举个例子,假设数组为:1 2 2 1,对应分配的糖果应该为:1 2 2 1。
正向 dp 得到的结果为:1 2 1 1,明显 a[3] > a[4] ,不符合,所以反向 dp 就是解决这个问题的。
代码:
#include <cstdio>
using namespace std;
const int N = 100000;
int n;
int a[N], f[N];
int main(void) {
scanf("%d", &n);
for ( int i = 0; i < n; ++i ) {
scanf("%d", a + i);
if ( !i ) f[i] = 1;
else {
if ( a[i] > a[i - 1] ) f[i] = f[i - 1] + 1;
else f[i] = 1;
}
}
int sum = f[n - 1];
for ( int i = n - 2; i >= 0; --i ) {
if ( a[i] > a[i + 1] && f[i] <= f[i + 1]) f[i] = f[i + 1] + 1;
sum += f[i];
}
printf("%d\n", sum);
return 0;
}