poj3017 -- Cut the Sequence

题意大意:将长度为n的序列分成若干段,使每段之和不大于m

 

且使各段中最大值之和最小,输出该值。

 

易知,f[i]:=min(f[j]+max(j+1,i));

 

f[i]表示前i个中划分出的最小值,max(l,r)lr中的最大值,转移条件为sum[j+1,i]<=m

 

这个方程时间复杂度为on^2)的,承受不了,所以要优化。

 

我们假设当 max(j,i)=max(j+1,i),,也就是说a[i]不是(j,i)之间的最大

 

值,由于很明显f是递增的(这个不用证明吧),所以 

 

f[j-1]+max(j,i)<=f[j]+max(j+1,i),也就是说j这个决策是不必要的,

 

所以只有a[j]max(j,i)j才为必要的决策

 

所以可以用单调队列来维护有效的决策

 

F[i]=max(f[q[x-1]]+a[q[x]])

 

因为队首决策不一定最优,所以用数据结构维护,我用的是堆,

 

但是还有一个问题,就是当x=h(队头)是,q[x-1]是不存在的,

 

所以我们必须加入一个非决策队头lm[i](使到i为止和不大于m

 

左边界,预先处理出来)。。这个目测就行了。。

 

P.S:理论上没错,但是pojdiscuss数据过了,但还是没ac。。。

 

不知怎的。。

 

  1 /*
  2  *Author:yzcstc
  3  *Typical:dp+queue+dui
  4  *Statue:unsolve;
  5  *Time:2013.01.20
  6  */
  7 #include <cstdio>
  8 #include <iostream>
  9 #include <fstream>
 10 #include <cstring>
 11 #include <fstream>
 12 #include <string>
 13 #include <cstdlib>
 14 const int maxn=111010;
 15 using namespace std;
 16 
 17 struct oo{ 
 18          long long z;
 19          int x;
 20 };
 21 
 22 int n, lm[maxn] , q[maxn] ,p[maxn];
 23 long long m, sum[maxn], f[maxn], a[maxn], tot;
 24 oo d[maxn],cc;
 25 
 26 void init(){
 27      scanf("%d",&n);
 28      scanf("%lld",&m);
 29      for (int i=1; i <= n; ++i){
 30          scanf("%lld",&a[i]);
 31          sum[i] = sum[i-1] + a[i];
 32      }
 33      int l=0;
 34      for (int i=1; i <= n; ++i){
 35           while (sum[i]-sum[l]>m) ++l;
 36           lm[i]=l;
 37      }
 38 }
 39 
 40 void updui(int i){
 41      int j=i << 1;
 42      while (j <= tot){
 43        if (j<tot && d[j].z>d[j+1].z)  ++j;
 44        if (d[i].z > d[j].z){
 45              cc = d[i];
 46              d[i] = d[j];
 47              d[j] = cc;
 48              p[d[i].x] = i;
 49              p[d[j].x] = j;
 50              i = j; 
 51              j <<= 1; 
 52        } else break;
 53      }
 54 }
 55 
 56 void downdui(int i){
 57     int j =i >> 1;
 58     while (j>0){
 59         if (d[i].z<d[j].z){
 60              cc = d[i];
 61              d[i] = d[j];
 62              d[j] = cc;
 63              p[d[i].x] = i;
 64              p[d[j].x] = j;
 65              i =j;
 66              j >>= 1; 
 67         } else break;
 68     }
 69 } 
 70 
 71 void solve(){
 72      int h = 1, t = 0 ; 
 73      tot = 0;
 74      for (int i=1; i <= n; ++i){
 75          while (h <= t && sum[i]-sum[q[h]]>m){
 76                d[p[q[h]]] = d[tot];
 77                p[d[tot].x] = p[q[h]];
 78                --tot;
 79                updui(p[q[h]]);
 80                ++h;
 81          }
 82          
 83          while (h <= t && a[i] > a[q[t]]){
 84                d[p[q[t]]] = d[tot];
 85                p[d[tot].x] = p[q[t]];
 86                --tot;
 87                updui(p[q[t]]);
 88                --t;
 89          }                                    
 90          
 91          ++t;  
 92          q[t]= i; 
 93          ++tot;  
 94          d[tot].x = i;
 95          d[tot].z = f[q[t-1]]+a[i];
 96          p[i] =tot;
 97          downdui(tot);
 98          
 99          int tt=p[q[h]];
100          d[tt].z = f[lm[i]] + a[q[h]];
101          downdui(tt);
102          updui(tt);
103          f[i] = d[1].z;
104      }
105      printf("%lld\n",f[n]);
106          
107 }
108 
109 int main(){
110      freopen("poj3017.in","r",stdin);
111      freopen("poj3017.out","w",stdout);
112      init();
113      solve();
114 }

 


 

 

 

posted on 2013-01-21 20:54  yzcstc  阅读(165)  评论(0)    收藏  举报