題目鏈接:
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3385
題目大意:
妖夢要準備一個party,所以需要許多食物,初始化妖夢的烹飪技能為L,每天妖夢有兩種選擇,一是選擇當天做L個食物,二是提升自己的烹飪技能為L+1。
但是幽幽子非常能吃,每天幽幽子都要吃Ai的食物,當沒食物吃后幽幽子會非常生氣,甚至想把妖夢批判一番。所以現在妖夢要保證做出的食物每天夠幽幽子吃的情況下盡量的多。
解題過程:
好久好久之前比賽的題,一直沒補,當初知道是貪心和棧,感覺這樣的思維題加簡單的數據結構的題非常難……也可能是直接接觸的題太少吧。
題目分析:
首先用棧去貪心的模擬,在能保證夠幽幽子吃的情況下,最多能夠將技能提高到幾級。
假設每天都提高等級并且將天數入棧,當當前剩下的食物不夠幽幽子吃的話,將上一次提升等級的地方換成做食物。如果還是不夠幽幽子吃的話,那么就是無解的。
因為提高等級是一個持久性的加成,當然是越早提升越好,所以每次將提高等級換做做食物的地方都是最晚的地方。
這樣求解出最高可以升到幾級后,再去求下最大能達到多少食物。
同樣效仿上面的操作,每次取出最近的提升等級的地方換成做食物,去維護一個最大值。
不過有可能有這樣的一個情況,在租個替換掉提升等級時,可能某個地方替換掉提升等級后食物就不夠幽幽子吃了。但是這種情況,求出的結果肯定比維護的最大值要小,因為現在食物不夠吃了,并且等級還低了,那么最后算出的剩余一定是更小的。
AC代碼:
#include <stdio.h>
#include <stack>
using namespace std;typedef long long LL;int main() {LL N, L;while (~scanf("%lld %lld", &N, &L)) {LL sum = 0;bool flag = true;stack<LL> ss;for (int i = 1; i <= N; i++) {LL eat;//每天要吃的食物數scanf("%lld", &eat);if (!flag)continue;ss.push(i);L++;//如果當前剩余的食物不夠的話,去替換掉之前提升等級while (sum < eat && !ss.empty()) {LL t = ss.top();L--;ss.pop();//將提升等級替換成做食物是很容易維護的,首先讓等級減一,加上等級,然后當從提升等級那天到至今的提升等級的加成減去sum += L - (i-t);}if (sum < eat) {flag = false;continue;}sum -= eat;}if (!flag) {printf("Myon\n");continue;}LL ans = sum;//求出最大值,類似上面的過程while (!ss.empty()) {LL t = ss.top();L--;ss.pop();sum += L - (N - t);ans = max(ans, sum);}printf("%lld\n", ans);}
}