【题解】P2627 [USACO11OPEN] Mowing the Lawn G

【题解】P2627 [USACO11OPEN] Mowing the Lawn G

题目跳转

数据量比较大,暴力肯定是不行的。只能考虑用动态规划的方式来做。
这道题有许多dp设计的思路,这里提供两个:

方法一:普通状态设计

定义dp[i][1/0]表示截止遍历到第i个元素时,选择第i个元素或不选第i个元素可以分别可以获得到的最大工作效率。

根据定义可以得到以下状态转移方程:

如果不选择第i个元素,那么很好想直接转移即可:dp[i][0]=max(dp[i1][0],dp[i1][1]
如果选择第i个元素,那么在区间[iK+1,i]内必须有一个奶牛不能工作,可以列出方程:dp[i][1]=max(dp[j][0],j=iK+1iEj

通过前缀和优化一下状态,就可以得到新的状态转移方程:dp[i][1]=max(dp[j][0]+sum[i]sum[j])。因为求最大值,而且i是不会变的,因此可以直接将sum[i]提前,可得dp[i][1]=max(dp[j][0]sum[j])+sum[i],(iK<=j<i)

可以看出只需要找到dp[j][0]sum[j]的最大值就可以了。因此我们只需要用一个单调数组维护一个长度为K
的区间中dp[j][0]sum[j]的最大值即可。

方法二:状态的再次压缩

在第一步的状态上加以优化,重新定义状态,令dp[i]表示为遍历到第i头奶牛后可以获得的最大效率。相同地,根据状态的定义可以得到状态转移方程dp[i]=max(dp[j1]sum[j])+sum[i]

代码很好写:

#include <iostream>
#include <algorithm>
using namespace std;

int n, k;
long long arr[100005], sum[100005];
long long b[100005], que[100005];
long long dp[100005];

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    cin >> n >> k;
    for (int i=1; i<=n; i++) {
        cin >> arr[i];
        sum[i] = sum[i-1] + arr[i];
    }
    // dp[i]表示选到第i头奶牛的时候可以获得的最大效率。
    // 枚举前面的奶牛就可以了。
    int head = 0, tail = 0;
    for (int i=1; i<=n; i++){
        b[i] = dp[i-1] - sum[i];
        while(head <= tail && que[head] < i-k) head++;
        while(head <= tail && b[i] > b[que[tail]]) tail--;
        que[++tail] = i;
        dp[i] =  b[que[head]] + sum[i];
    }
    cout << dp[n] << endl;
    return 0;
}
posted @   Macw  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示