题目大意
给定各个熊孩子的排名值,按照排名大小分糖果(将rating value理解成功劳值更贴切,功劳越大分的越多,注意一下功劳相同所分的糖果不一定相同),输出最少消耗糖果数。
解题思路
不得不吐槽一下这个题目,根本就没说清楚功劳相同怎样分配,只是说了功劳大者比邻居要多(注意这里其实隐含了相同的分配情况)。WA了几次分析数据才弄清楚应该如何处理相同功劳的情况。显然当功劳相同时,若这一组相同功劳两边有其他功劳值(如1 2 3 3 3 1)则该相同功劳值的两端(第3和第5个功劳值1)分配不同的糖果数目,且只影响其邻近的一位数(2影响第3个3,1影响第5个3),其数值分别由前后两数决定(分上升趋势和下降趋势讨论),而中间功劳值则恒分配1的糖果(故糖果应该分配为1 2 3 1 2 1)。若两边都没有值(即2 2 2 2),则无疑全都是1。把最纠结的部分搞定后思路就比较清晰了,只需要探查一下每一次的下降长度与当前上升的波峰进行比较取较大者就行了。
对for循环遍历的每一个rating[i]:
(1)若i不为最后一个数,判断rating[i]是否小于ranting[i+1],若是则糖果数增加一,若否,转(2)。
若i为最后一个数,转(3)。
(2)向前探查其最长的下降长度并将结果与当前波峰(第一个开始下降的数)比较,若较大则修改当前第i个小朋友获得的糖果数,并依次从当前(i)开始将处于下降序列的小朋友一一赋予递减的糖果,若较小,则从下一个小朋友开始依次赋予递减的糖果数。
(3)当前为最后一个小朋友若比前一个小朋友功劳大,则比其多一个糖果,若与其功劳相等,则只获得一个糖果。若比前一个小则无需处理,因为已经包含在(2)中了。
总结
要想清楚再动笔写白板,理清楚思路后还要注意好细节及变量大小和数组边界的控制,另外命名最好更科学,比如count可以用cur代替。尤其注意一些特殊情况,比如当输入为一人或者零人的时候。
代码(附测试数据)
#include<iostream>
#include<set>
#include<vector>
#include<map>
using namespace std;
int candy(vector<int> &ratings)
{
int count = 0, sum = 0;//记录当前应该分配的糖果数和糖果总数
int n = ratings.size();
if (n-1==0)return 1;
for (int i = 0; i < n; i ++){
if (i+1 < n){
if (i && ratings[i]==ratings[i-1])count--;
sum += (++count);
if (ratings[i] >= ratings[i+1]) {
int j = i, k = i+1;
sum-=count;
if (ratings[j] > ratings[k]){
while (ratings[j] > ratings[k] && k < n){
k ++; j ++;
}
if (k-i > count)count = k-i;
}
sum += count;
count = k-i;
for (j = i+1; j < k; j ++){
sum += (-- count);
}
i = k-1;
}
}
if (i == n-1){
if (ratings[i] > ratings[i-1]) sum+=(++ count);
else if (ratings[i] == ratings[i-1])sum++;
}
}
return sum;
}
int main()
{
int n;
while (cin >> n){
vector <int> a;
a.clear();
for (int i = 0; i < n; i ++){
int tmp;
cin >> tmp;
a.push_back(tmp);
}
cout << "total candies:"<<candy(a)<<endl;
}
return 0;
}
/*
3
1 1 1
10
5 1 1 1 10 2 1 1 1 3
5
4 2 3 4 1
3
1 0 2
*/