loj10177. 「一本通 5.5 例 3」修剪草坪

思路:
  状态:dp【i】【0】表示前i个元素,i号元素不取的情况,dp【i】【1】表示前i个元素,第i个取的情况。

  ·方程:dp【i】【1】=max【i-m <= j < i】(dp【j】【0】 - sum【j】) + sum【i】

     dp【i】【0】=max(dp【i-1】【0】, dp【i-1】【1】);

  优化:单调队列

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 200010;
inline int qread(){
    register int ch = getchar(), flag = 0, x = 0;
    while(ch < '0' || ch > '9')    {if(ch == '-') flag = 1; ch = getchar();}
    while(ch >= '0' && ch <= '9')    x = 10 * x + ch - 48, ch = getchar();
    return flag ? -x : x;
}
long long qu[maxn];
int head = 1, tail, pos[maxn];
long long sum[maxn];
long long data[maxn];
long long dp[maxn][2];
int n, m;
void dpmax(){
    for(int i = 1; i <= n; ++i){
        while(pos[head] < i - m + 1 && head <= tail)                        head++;
        while(qu[tail] <= dp[i - 1][0] - sum[i - 1] && head <= tail)        tail--;
        pos[++tail] = i;    qu[tail] = dp[i - 1][0] - sum[i - 1];
        dp[i][1] = qu[head] + sum[i];
        dp[i][0] = max(dp[i - 1][0], dp[i - 1][1]);    
    }
}
int main(void){
    n = qread(), m = qread();
    for(int i = 1; i <= n; ++i)
        data[i] = qread();
    for(int i = 1; i <= n; ++i)
        sum[i] = sum[i - 1] + data[i];    
    dpmax();
    cout << max(dp[n][0], dp[n][1]) << endl;    
    return 0;
}

 

posted @ 2018-08-20 11:37  junk_yao  阅读(262)  评论(0编辑  收藏  举报