VIJOS P1617 超級教主

描述

LHX教主很能跳,因爲Orz他的人太多了。教主跳需要消耗能量,每跳1米就會消耗1點能量,如果教主有很多能量就能跳很高。

教主爲了收集能量,來到了一個神祕的地方,這個地方凡人是進不來的。在這裏,教主的正上方每100米處就有一個能量球(也就是這些能量球位於海拔100,200,300……米處),每個能量球所能提供的能量是不同的,一共有N個能量球(也就是最後一個能量球在N×100米處)。教主爲了想收集能量,想跳着吃完所有的能量球。教主可以自由控制他每次跳的高度,接着他跳起把這個高度以下的能量球都吃了,他便能獲得能量球內的能量,接着吃到的能量球消失。教主不會輕功,教主不會二段跳,所以教主不能因新吃到的能量而變化此次跳躍的高度。並且教主還是生活在地球上的,所以教主每次跳完都會掉下來。

問教主若要吃完所有的能量球,最多還能保留多少能量。

格式

輸入格式

第1行包含兩個正整數N,M,表示了能量球的個數和LHX教主的初始能量。

第2行包含N個非負整數,從左到右第I個數字依次從下向上描述了位於I×100米位置能量球包含的能量,整數之間用空格隔開。

輸出格式

僅包括一個非負整數,爲教主吃完所有能量球后最多保留的能量。

樣例1

樣例輸入1[複製]

3 200
200 200 200

樣例輸出1[複製]

400

限制

對於10%的數據,有N≤10;
對於20%的數據,有N≤100;
對於40%的數據,有N≤1000;
對於70%的數據,有N≤100000;
對於100%的數據,有N≤2000000。

保證對於所有數據,教主都能吃到所有的能量球,並且能量球包含的能量之和不超過2^31-1。

時限1s。

提示

第1次跳100米,得到200能量,消耗100能量,所以落地後擁有300能量。

第2次跳300米,吃到剩下的第3棵能量球,消耗擁有的300能量,得到400能量。

若第1次跳200米,第2次跳300米,最後剩餘300能量。

題意:略

思路: DP + 單調隊列

數據規模是2000000, 只能用一維DP。

dp[i] 表示 吃完前i個, 剩下最大的能量.

先想個 O(N^2)的。

dp[i] = max(dp[i], dp[j] + sum[i] - sum[j] - i * 100);

化簡爲 dp[i] = max(dp[i], dp[j] - sum[j]) + sum[i] - i * 100;

因爲每次都是找  Max(dp[j] - sum[j]); 而且要花費N次。 但是, i, i + 1 找的區間只是錯開一位。

所以可以用隊列優化。維護一個單調遞減隊列。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

//單調性DP

const int V = 2000000 + 50;
const int MaxN = 80 + 5;
const int mod = 10000 + 7;
const __int64 INF = 0x7FFFFFFFFFFFFFFFLL;
const int inf = 0x7fffffff;
int dp[V], sum[V]; //dp[i] 表示吃完前i個, 剩餘的最大能量
int m, n;
int Que[V], front, rear; //單調遞減隊列優化   Max(dp[j] - sum[j]);
void pushBack(int i) {
    while(front < rear && dp[i] - sum[i] > dp[Que[rear - 1]] - sum[Que[rear - 1]])
        rear--;
    Que[rear++] = i;
}
int Get(int i) {
    while(front < rear && dp[Que[front]] < i * 100) //去掉無法到達該高度
        front++;
    return Que[front];
}
int main() {
    int i, j;
    scanf("%d%d", &n, &m);
    for(i = 1; i <= n; ++i) {
        int temp;
        scanf("%d", &temp);
        sum[i] = sum[i - 1] + temp;
    }
    dp[0] = m;
    Que[rear++] = 0;
    for(i = 1; i <= n; ++i) {
        int id = Get(i);
        if(dp[id] >= i * 100)
            dp[i] = max(dp[i], dp[id] + (sum[i] - sum[id]) - i * 100);
        pushBack(i);
    }
    printf("%d\n", dp[n]);
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章