AcWing 1087. 修剪草坪
题意:
有n个数,不能选超过连续的k个数,问所能选的最大值是多少?
题解:
我们首先分析dp过程:
dp[i]表示选择完前i个数的最大值
sum[i]表示前i项和
对于第i个数,它有两个情况,选和不选
1.不选,dp[i]=dp[i-1]
2.选,那么以i为结尾的连续长度可以为1,也可以为2。。。,我们设所选的连续长度为j(1<=j<=k),那么这个区间就是[i-j+1,i],而第i-j个数就不选,再往前的区间答案就是dp[i-j-1]
所以此时dp[i]=dp[i-j-1]+sum[i]-sum[i-j]
i是固定的,j是不固定的,所以我们将式子变下形
dp[i]=(dp[i-j-1]-sum[i-j]) +sum[i] = g[i-j]+sum[i]
令g[i]=dp[i-1]-sum[i],这样我们要让dp[i]最大,就要让g[i-j]最大,单调队列维护下降序列得到区间长度为k的g[i]的最大值
代码:
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\n",a,b);
typedef long long ll;
using namespace std;inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
const int maxn=1e5+9;
ll f[maxn];
ll s[maxn];
int q[maxn];
ll g(int i){if(i==0)return 0;return f[i-1]-s[i];
}
int main()
{int n,k;cin>>n>>k;for(int i=1;i<=n;i++){cin>>s[i];s[i]+=s[i-1];}int hh=0,tt=0;for(int i=1;i<=n;i++){if(q[hh]+k<i)hh++;f[i]=max(f[i-1],g(q[hh])+s[i]);while(hh<=tt&&g(q[tt])<=g(i))tt--;q[++tt]=i;}cout<<f[n];return 0;
}
/*
dp[i]=dp[i-1]
当我们选择连续长度为j时,(1<=j<=k)
dp[i]=dp[i-j-1]+s[i]-s[i-j]
*/