1599:【 例 3】修剪草坪(单调队列优化dp)

l i n k link link
题意:一个长度为 n n n的数组,你可以从中取若段,每段的长度不能超过 K K K,问取得若干段的最大值时多少?

题解:
d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] ) dp[i][0] = max(dp[i-1][0],dp[i-1][1]) dp[i][0]=max(dp[i1][0],dp[i1][1]);
d p [ i ] [ 1 ] = m a x ( d p [ k ] [ 0 ] + s u m [ i ] − s u m [ k ] ) dp[i][1] = max(dp[k][0]+sum[i]-sum[k]) dp[i][1]=max(dp[k][0]+sum[i]sum[k])其中 ( i − K < = k < = i ) (i-K<=k<=i) (iK<=k<=i);
化简得: d p [ i ] [ 1 ] = s u m [ i ] − m a x ( d p [ k ] [ 0 ] − s u m [ k ] ) dp[i][1] = sum[i]-max(dp[k][0]-sum[k]) dp[i][1]=sum[i]max(dp[k][0]sum[k])其中 ( i − K < = k < = i ) (i-K<=k<=i) (iK<=k<=i);
而其中 m a x ( d p [ k ] [ 0 ] − s u m [ k ] ) max(dp[k][0]-sum[k]) max(dp[k][0]sum[k])可以用当掉队列求得。

c o d e : code: code

#include <bits/stdc++.h>
#define ll long long
#define pi pair<int,int>
#define mk make_pair
#define pb push_back
using namespace std;

const int maxn = 1e5+100;
ll a[maxn],q[maxn],sum[maxn],dp[maxn][2];
int main()
{
    
    
	int n,k;
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)scanf("%lld",a+i),sum[i] = sum[i-1] + a[i];
	k+=1;
	int head = 1,tail = 0;
	for(int i=1;i<=n;i++)
	{
    
    
		dp[i][0] = max(dp[i-1][0],dp[i-1][1]);
		while(head <= tail && i-q[head]+1 > k)++head;
		while(head <= tail && dp[q[tail]][0] - sum[q[tail]] < dp[i][0] - sum[i])--tail;
		q[++tail] = i;
		if(i < k)dp[i][1] = sum[i];
		else dp[i][1] = sum[i] + dp[q[head]][0] - sum[q[head]];
	}
	printf("%lld\n",max(dp[n][0],dp[n][1]));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44499508/article/details/106734932