AcWing 1087. 修剪草坪----和基础课一致的单调队列写法
原题链接
中等
作者:
dfs你是要毁了我吗
,
2024-04-15 09:48:02
,
所有人可见
,
阅读 3
//f[i]表示从前i头中选的合法方案的集合 属性max值
//思路是枚举前一个断点位置
//对于f[i]断点j必然存在于[i-k,i]中(这样保证合法 不连续太多)
//然后f[i]==max{f[j-1]+w[j+1]+...+w[i] ,...,...,... }; 然后变量是f[j-1]-s[j]设为g
//利用单调队列每次O(1)拿出最大的g值
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int n, m;
LL s[N];
LL f[N];
int q[N];
LL g(int i)
{
if (!i) return 0;
return f[i - 1] - s[i];
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ )
{
scanf("%lld", &s[i]);
s[i] += s[i - 1];
}
//刚开始有一个元素q[0]==0; (s[0]==0)
int hh = 0, tt = 0;q[0]=s[0];
//其实写法上可以和基础课模板一摸一样
//yxc视频写的代码我改动了以下 更具备一致性
for (int i = 1; i <= n; i ++ )
{
if(q[tt]-q[hh]>=m) hh ++ ;
while (hh <= tt && g(q[tt]) <= g(i)) tt -- ;
q[ ++ tt] = i;
f[i]=g(q[hh])+s[i];
}
printf("%lld\n", f[n]);
return 0;
}