[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;
}
posted @ 2022-07-06 11:00  Epoch_L  阅读(12)  评论(0编辑  收藏  举报