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[i−1][0],dp[i−1][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) (i−K<=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) (i−K<=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;
}