BZOJ-1915: [Usaco2010 Open]奶牛的跳格子游戏

[文章目录]

Description

奶牛们正在回味童年,玩一个类似跳格子的游戏,在这个游戏里,奶牛们在草地上画了一行N个格子,(3 <=N <= 250,000),编号为1..N。就像任何一个好游戏一样,这样的跳格子游戏也有奖励!第i个格子标有一个数字V_i(-2,000,000,000 <=V_i <= 2,000,000,000)表示这个格子的钱。奶牛们想看看最后谁能得到最多的钱。规则很简单: * 每个奶牛从0号格子出发。(0号格子在1号之前,那里没钱) * 她向N号格子进行一系列的跳跃(也可以不跳),每次她跳到的格子最多可以和前一 个落脚的格子差K格(1 <= K <= N)(比方说,当前在1号格,K=2, 可以跳到2号和3号格子) *在任何时候,她都可以选择回头往0号格子跳,直到跳到0号格子。另外,除了以上规则之外,回头跳的时候还有两条规则: *不可以跳到之前停留的格子。 *除了0号格子之外,她在回来的时候,停留的格子必须是恰巧过去的时候停留的某个格子的前一格(当然,也可以跳过某些过去时候停留的格子)。简单点说,如果i号格子是回来 停留的格子,i+1号就必须是过去停留的格子,如果i+1号格子是过去停留的格子,i号格子不一定要是回来停留的格子。(如果这里不太清楚的可以去看英文原文)她得到的钱就是所有停留过的格子中的数字的和,请你求出最多奶牛可以得到的钱数。

DP状态设为回来的路径,将跳过的正权点累计入代价进行DP,斜率优化即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define N 251000
int n,m,a[N];
int q[N];
ll s[N],dp[N];
int main()
{
    scanf("%d%d",&n,&m);
    int i;
    for(i=1;i<=n;++i)
    {
        scanf("%d",a+i);
        s[i]=(a[i]>0) ? s[i-1]+a[i] : s[i-1];
    }
    int l=1,r=1;
    memset(dp,0xef,sizeof dp);
    dp[0]=0;
    for(i=2;i<=n;++i)
    {
        while(l<=r&&q[l]<i-m) ++l;
        if(l<=r) dp[i]=dp[q[l]]-s[q[l]]+s[i-2]+a[i]+a[i-1];
        while(l<=r&&dp[q[r]]-s[q[r]]<=dp[i-1]-s[i-1]) --r;
        q[++r]=i-1;
    }
    // for(i=0;i<=n;++i) printf("%lld ",dp[i]);
    ll ans=s[m];
    for(i=1;i<=n;++i) ans=max(ans,dp[i]+s[min(n,i+m-1)]-s[i]);
    printf("%lld",ans);
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注