POJ3017

题意

   将一段序列分割为任意段,每一段的连续和不超过M,使得每一段最大值的和最小.

分析

   用单调队列进行优化的dp。单调队列可以维护可以影响当前区间的最大值。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 #include <queue>
 6 using namespace std;
 7 const int maxn=100000+100;
 8 int a[maxn];
 9 long long f[maxn];
10 long long sum[maxn];
11 int n;
12 long long m;
13 int main(){
14     scanf("%d%lld",&n,&m);
15     sum[0]=0;
16     int ok=1;
17     for(int i=1;i<=n;i++){
18         scanf("%d",&a[i]);
19         sum[i]=sum[i-1]+a[i];
20         if(a[i]>m)ok=0;
21     }
22     if(!ok){printf("-1");return 0;}
23     f[0]=0;
24     f[1]=a[1];
25     deque<int>q;
26     int beg=1;
27     for(int i=1;i<=n;i++){
28             while(!q.empty()&&a[i]>=a[q.back()])q.pop_back();
29             while(sum[i]-sum[beg-1]>m&&beg<i)beg++;
30             q.push_back(i);
31             while(q.front()<beg&&!q.empty())q.pop_front();
32             f[i]=f[beg-1]+a[q.front()];
33             for(int k=1;k<=q.size();k++){
34                 int b=q.front();
35                 q.pop_front();
36                 if(!q.empty())
37                 f[i]=min(f[i],f[b]+a[q.front()]);
38                 q.push_back(b);
39             }
40     }
41     printf("%lld",f[n]);
42 return 0;
43 }
View Code
原文地址:https://www.cnblogs.com/LQLlulu/p/8825074.html