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 }