P2627 [USACO11OPEN] Mowing the Lawn G 学习笔记

· · 个人记录

problem

/*
很明显的dp
我们设 f[i, j] 为第 i 头牛在 j 状态时(0不选 1选)最大贡献
此时对于 f[i, 1],取 max(f[j, 0] + pre[i] - pre[j]) (j∈[i - k, i])
然而会TLE一个点(数据还是水)
注意到 max(f[j, 0] + pre[i] - pre[j]) => max(f[j, 0] - pre[j]) + pre[i]
于是我们需要一个单调队列,维护 max(f[j, 0] - pre[j])
最终时间复杂度 O(n * 4 + n),抛开常数不谈,O(n)
*/
#include "bits/stdc++.h"
#define For(i, l, r) for(int i = (l) ; i <= (r) ; ++i)
typedef long long ll ;
using namespace std ;
const int N = 100005 ;
ll n, k, f[N][2], a[N], pre[N] ;
int q[N], l, r ;
int main()
{
    ios::sync_with_stdio(false) ;
    cin.tie(0) ; cout.tie(0) ;
    cin >> n >> k ;
    For(i, 1, n)
    {
        cin >> a[i] ;
        pre[i] = pre[i - 1] + a[i] ;
    }
    For(i, 1, n)
    {
        f[i][0] = max(f[i - 1][0], f[i - 1][1]) ;
        while(q[l] < i - k && l <= r) l++ ;
        f[i][1] = f[q[l]][0] - pre[q[l]] + pre[i] ;
        while(f[i][0] - pre[i] > f[q[r]][0] - pre[q[r]] && l <= r) r-- ;
        q[++r] = i ;
    }
    cout << max(f[n][0], f[n][1]) ;
    return 0 ;
}