[USACO11OPEN]Mowing the Lawn G
题解
考虑DP,我们设 \(f[i]\) 表示前 \(i\) 头奶牛所能取到的最大值,则在 \((i-k,i)\) 区间中必须有一头奶牛不取,假设它是 \(j\),则
\[f[i]= \max(f[j-1]+s[i]-s[j])
\]
其中 \(s\) 数组表示前缀和。
观察转移方程,发现 \(s[i]\) 是常量,从括号内提出来。
\[f[i]= \max(f[j-1]-s[j])+s[i]
\]
那么,如何取 \(\max\) 呢,使用单调队列记录即可,记录 \(f[j-1]-s[j]\) 单调递减的单调队列即可,答案为 \(f[n]\)。
Code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
void read(int &x)
{
char ch=getchar();
int r=0,w=1;
while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar();
while(isdigit(ch))r=(r<<3)+(r<<1)+(ch^48),ch=getchar();
x=r*w;
}
const int N=1e5+100;
int s[N],line[N],f[N],t[N];
main()
{
int n,k;
read(n);read(k);
for(int i=1,x;i<=n;i++)
read(x),s[i]=s[i-1]+x;
int head=1,tail=0;
for(int i=0;i<=n;i++)
{
if(i>0)t[i]=f[i-1]-s[i];
while(head<=tail&&t[i]>t[line[tail]])tail--;
line[++tail]=i;
while(head<=tail&&line[head]<i-k)head++;
f[i]=t[line[head]]+s[i];
}
cout<<f[n];
return 0;
}