1599:[例3]芝刈り(単調なキュー最適化dp)

リンクリンク l i n k
質問の意味:長さnnnの配列。そこから複数のセグメントを取得でき、各セグメントの長さはKKを超えることはできませんK、いくつかのセグメントの最大値はいくつですか?

解:
dp [i] [0] = max(dp [i-1] [0]、dp [i-1] [1])dp [i] [0] = max(dp [i-1] [0 ]、dp [i-1] [1])d p [ i ] [ 0 ]=m a x d p [ i1 ] [ 0 ] d p [ i1 ] [ 1 ] ;
dp [i] [1] = max(dp [k] [0] + sum [i]-sum [k])dp [i] [1] = max(dp [k] [0] + sum [i] -sum [k])d p [ i ] [ 1 ]=m a x d p [ k ] [ 0 ]+s u m [ i ]s u m [ k ] 其中(i − K <= k <= i)(iK <= k <= i)K<=k<=i ;
化简得:dp [i] [1] = sum [i]-max(dp [k] [0]-sum [k])dp [i] [1] = sum [i] -max( dp [k] [0] -sum [k])d p [ i ] [ 1 ]=s u m [ i ]m a x d p [ k ] [ 0 ]s u m [ k ] 其中(i − K <= k <= i)(iK <= k <= i)K<=k<=i ;
そして、ここでmax(dp [k] [0]-sum [k])max(dp [k] [0] -sum [k])m a x d p [ k ] [ 0 ]s u m [ k ] は、キューをポーンすることで取得できます。

コード:コード: c o d e

#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