luogu 2627 修剪草坪

题目描述

在一年前赢得了小镇的最佳草坪比赛后,Farm John变得很懒,再也没有修剪过草坪。现在,新一轮的最佳草坪比赛又开始了,Farm John希望能够再次夺冠。

然而,Farm John的草坪非常脏乱,因此,Farm John只能够让他的奶牛来完成这项工作。Farm John有N(1 <= N <= 100,000)只排成一排的奶牛,编号为1...N。每只奶牛的效率是不同的,奶牛i的效率为E_i(0 <= E_i <= 1,000,000,000)。

靠近的奶牛们很熟悉,因此,如果Farm John安排超过K只连续的奶牛,那么,这些奶牛就会罢工去开派对:)。因此,现在Farm John需要你的帮助,计算FJ可以得到的最大效率,并且该方案中没有连续的超过K只奶牛。

输入格式

第一行:空格隔开的两个整数 N 和 K

第二到 N+1 行:第 i+1 行有一个整数 E_i

输出格式

第一行:一个值,表示 Farm John 可以得到的最大的效率值。

输入输出样例

输入 #1

5 2
1
2
3
4
5

输出 #1

12

分析

(1) 记得开long long

(2) 左闭右开的对列访问队尾要用 r - 1

(3)将方程变形使其可以用单调队列优化

(4)当状态不对,空间大了的话,可以尝试将状态下放到每一个元素上

(5)注意初始状态,初始化,边界条件。比如开始时还没到k时,可以在队列中插入一个0。以免将第一个漏掉(因为转移是用的dp[q[l]][0])其中无法包含第一个

代码

/***************************
User:Mandy.H.Y
Language:c++
Problem:luogu2627
Algorithm:
Date:2019.8.30 
***************************/

#include<bits/stdc++.h>
#define Max(x,y) ((x) > (y) ? (x) : (y))
#define Min(x,y) ((x) < (y) ? (x) : (y))

using namespace std;

const int maxn = 1e5 + 5;

int n,k,l,r;
long long dp[maxn][3];
long long sum[maxn],q[maxn];
//dp[第i只牛][是否包含自身] 
template<class T>inline void read(T &x){
    x = 0;bool flag = 0;char ch = getchar();
    while( ! isdigit(ch)) flag |= ch == '-',ch = getchar();
    while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
    if(flag) x = -x;
}

template<class T>void putch(const T x){
    if(x > 9) putch(x / 10);
    putchar(x % 10 | 48);
}

template<class T>void put(const T x){
    if(x < 0) putchar('-'),putch(-x);
    else putch(x);
}

void file(){
    freopen("testdata.in","r",stdin);
//    freopen("2627.out","w",stdout);
}

void readdata(){
    read(n);read(k);
    for(int i = 1;i <= n; ++ i){
        read(sum[i]);
        sum[i] += sum[i-1];
    }
}

void work(){
    q[r++] = 0;//主要是为了前几个还没到k的考虑
    //因为 dp[q[l]][0] - sum[q[l]]可能小于0 , 
    //所以前面可能出现连加,加上0以免将前几个漏了
    //因为  dp[q[l]][0]不包括自身 
    for(int i = 1;i <= n; ++ i){
    
        while(l < r && q[l] < i-k) l++;
        
        dp[i][0] = Max(dp[i-1][0],dp[i-1][1]);
        if(l < r) dp[i][1] = dp[q[l]][0] - sum[q[l]] + sum[i];
        else dp[i][1] = sum[i] - sum[i-1];
        
        while(l < r && dp[q[r-1]][0] - sum[q[r-1]] <= dp[i][0] - sum[i]) r--;
        //注意是r - 1; 
        
        q[r++] = (long long)i;
    }
    
    put(Max(dp[n][0],dp[n][1]));
}

int main(){
//    file();
    readdata();
    work();
    return 0;
}
View Code
非做顽石不可,哪管他敬仰暗唾
原文地址:https://www.cnblogs.com/Mandy-H-Y/p/11433096.html