【Foreign】划分序列 [线段树][DP]

划分序列

Time Limit: 20 Sec  Memory Limit: 256 MB

Description

  

Input

  

Output

  仅一行一个整数表示答案。

Sample Input

  9 4
  1 1 1 3 2 2 1 3 1

Sample Output

  5

HINT

  

Main idea

  将序列分为若干段,使得和最大的那一段最小,值可以为负。

Source

  首先,显然都想到了二分答案

  我们先把都为正数或负数的情况写了:Ai>=0的时候求出最小的划分段数x,若x<=K则表示当前答案可行;Ai<=0的时候求出最大的划分段数x,若x>=K则表示当前答案可行。然后再打了暴力,接着我们对拍一下,惊讶地发现了一个规律:若最小划分段数为L,最大划分段数为R,当L<=K<=R时则可以更新

  然后我们用DP来求L和R,也就是:若一段的和满足<=mid,则可以分为一段。

  然后我们发现,可以用线段树优化寻找1~i-1中的最小值或最大值,这样判断就可以满足效率了。

Code

  1 #include<iostream>  
  2 #include<algorithm>  
  3 #include<cstdio>  
  4 #include<cstring>  
  5 #include<cstdlib>  
  6 #include<cmath>  
  7 #include<vector>
  8 using namespace std;
  9 typedef long long s64;
 10 
 11 const int INF = 2147483640;
 12 const int ONE = 5e4+5;
 13 
 14 int n,block;
 15 int L,R;
 16 int x,sum[ONE],s[ONE];
 17 int li[ONE],li_num; 
 18 int f_min[ONE],f_max[ONE];
 19 int res_min,res_max;
 20 int Zero;
 21 
 22 int get()
 23 {
 24         int res=1,Q=1;    char c;
 25         while( (c=getchar())<48 || c>57)
 26         if(c=='-')Q=-1;
 27         if(Q) res=c-48; 
 28         while((c=getchar())>=48 && c<=57) 
 29         res=res*10+c-48; 
 30         return res*Q; 
 31 }
 32 
 33 namespace Seg
 34 {
 35         struct power
 36         {
 37             int minn;
 38             int maxx;
 39         }Node[ONE];
 40         
 41         void Build(int i,int l,int r)
 42         {
 43             Node[i].minn = INF;
 44             Node[i].maxx = -INF;
 45             if(l==r) return;
 46             int mid=(l+r)>>1;
 47             Build(i<<1,l,mid);    Build(i<<1|1,mid+1,r);
 48         }
 49         
 50         void Update(int i,int l,int r,int L,int x,int PD)
 51         {
 52             if(l==r)
 53             {
 54                 if(!PD) Node[i].minn = x;
 55                 else Node[i].maxx = x;
 56                 return;
 57             }
 58             int mid=(l+r)>>1;
 59             if(L<=mid) Update(i<<1,l,mid,L,x,PD);
 60             else Update(i<<1|1,mid+1,r,L,x,PD);
 61             Node[i].minn = min(Node[i<<1].minn, Node[i<<1|1].minn);
 62             Node[i].maxx = max(Node[i<<1].maxx, Node[i<<1|1].maxx);
 63         }
 64         
 65         void Query(int i,int l,int r,int L,int R)
 66         {
 67             if(L<=l && r<=R)
 68             {
 69                 res_min=min(res_min, Node[i].minn);
 70                 res_max=max(res_max, Node[i].maxx);
 71                 return;
 72             }
 73             int mid=(l+r)>>1;
 74             if(L<=mid) Query(i<<1,l,mid,L,R);
 75             if(mid+1<=R) Query(i<<1|1,mid+1,r,L,R);
 76         }
 77 }
 78 
 79 int Check(int mid)
 80 {
 81         Seg::Build(1,1,li_num);
 82         Seg::Update(1,1,li_num, Zero,0,0);
 83         Seg::Update(1,1,li_num, Zero,0,1);
 84         for(int i=1;i<=n;i++)
 85         {
 86             int pos = lower_bound(li+1,li+li_num+1,sum[i] - mid) - li;
 87             res_min = INF;    res_max = -INF;    Seg::Query(1,1,li_num, 1,pos);
 88             f_min[i] = res_min + 1;
 89             f_max[i] = res_max + 1;
 90             Seg::Update(1,1,li_num, s[i],f_min[i],0);
 91             Seg::Update(1,1,li_num, s[i],f_max[i],1);
 92         }
 93         return (f_min[n]<=block && block<=f_max[n]);
 94 }
 95 
 96 
 97 int main()
 98 {      
 99         n=get();    block=get();
100         li[++li_num] = 0;
101         for(int i=1;i<=n;i++)
102         {
103             x=get();
104             li[++li_num] = sum[i] = sum[i-1] + x;
105             if(x < 0) L+=x; else R+=x; 
106         }
107         
108         sort(li+1,li+li_num+1);
109         li_num = unique(li+1,li+li_num+1) - li - 1;
110         
111         for(int i=1;i<=n;i++)
112             s[i]=lower_bound(li+1,li+li_num+1, sum[i]) - li;
113         Zero = lower_bound(li+1,li+li_num+1, 0) - li;
114         
115         while(L < R - 1)
116         {
117             int mid=(L+R)>>1;
118             if(Check(mid)) R = mid;
119             else L = mid;
120         }
121         
122         if(Check(L)) printf("%d",L);
123         else printf("%d",R);
124 }
View Code
原文地址:https://www.cnblogs.com/BearChild/p/6532994.html