vito和火锅食材(单调队列优化dp)

一道典型的单调队列优化dp,想了好久才搞清楚。

是典型的限制长度的最大子段和,基本的dp方程应该是dp[i]=sum[i]-min{sum[j]}

其中sum是原数组的前缀和,j的下标应当满足(i-j)<t,t是限制的长度。

单调队列里塞进下标,维护这些下标处的前缀和单调不减,每次更新答案为sum[i]-sum[j]即可。

 坑点究极多,每次更新ans=max(ans,sum[i])还不行,一定得在一开始往队列里塞个下标0进去才能维护得住单调性。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=1e18;
const int maxn=300005;

int s,t;
ll a,sum[maxn],ans=-inf,mx=-inf;
deque<ll> q;

int main(){
    scanf("%d%d",&s,&t);
    for(int i=1;i<=s;++i){
        scanf("%lld",&a);
        mx=max(mx,a);
        sum[i]=sum[i-1]+a;
    }
    q.push_back(0);
    for(int i=1;i<=s;++i){
//        ans=max(ans,sum[i]);
        while(!q.empty()&&sum[i]<sum[q.back()])
            q.pop_back();
        while(!q.empty()&&i-q.front()>t)
            q.pop_front();
        q.push_back(i);
        ans=max(ans,sum[i]-sum[q.front()]);
//        for(int j=0;j<q.size();++j)
//            cout<<q[j]<<' ';cout<<endl;
    }
    if(mx<=0) printf("%lld",mx);
    else printf("%lld",ans);
    return 0;
}
/*
3 3
2 -1 3
*/

猜你喜欢

转载自www.cnblogs.com/oneman233/p/11456661.html
今日推荐