POJ3245 神题 二分+DP+单调队列+堆/线段树/平衡树
来源:互联网 发布:乐视手机mac怎么修改 编辑:程序博客网 时间:2024/06/08 20:09
未做POJ3017Cut the Sequence者请先忽略此文
首先膜拜杜神犇:http://hi.baidu.com/billdu/blog/item/215a8defcbc8a43c2df53498.html
若有不懂再看本文
题目大意:给定长度为n的序列对A,B,将序列对分为若干连续子段使其满足以下性质
1:任意两对元素(Ap,Bp)和(Aq,Bq)若p,q不在同一段中且有p<q 则Bp>Aq
2:定义Mi为第i段包含的元素中A的最大值,即Mi = max{Ali, Ali+1, ..., Ari}, 1 ≤ i ≤ p
li ri为第i段的最左端和最右端 p为段数。
使得sigma{Mi}<=lima,lima为一个给定的值。
Task:
定义Si为第i段的B值的和。
满足上述条件下使得max{Si:1 ≤ i ≤ p}最小
思路:
其实预处理的思路并不是我的,来源于杜神犇,剩下的二分大家基本上都可以想出来,DP其实和POJ3017是一样的,我是先做了3017的。
这题难在满足第一个条件上,如果正向思考是不可以的(或者说很难),那么逆向思考。
只要是p<q且Bp<=Aq的必须在一起,
引用杜神犇的话:
对于第一个条件,我们不难发现,对于任意的p < q,如果Bp <= Aq,那么从p到q的这一段都必须在一个区间里。我们可以抽象为一张N个节点的图,如果[p, q]必须在一个区间里,那么连边(p, p + 1), (p + 1, p + 2), ..., (q - 1, q)。找到所有这样的关系,我们可以发现,所有的连通块都必须属于一个区间,所以说对于每一个连通块,我们将其缩成一个数对,它的A值为连通块中所有数对的A的最大值,B为连通块中所有数对的B的和。经过这样的过程,我们在以后的工作中就不用考虑第一个条件了。
但裸做是不可以的。
由于子段是连续的,那么对于任意一个p,只有最大的q满足Bp<=Aq才有用
那么只需在扫描到Bp之前(或之时)Bp<=Aq的所有q都扫描到就可以了。
那么就分别对A,B降序排序,记录A,B原位置,由于A,B排好序了,只要扫描到Bp时,将所有的Bp<=Aq的Aq扫到就可以了。
那么算法流程就出来了:
step1:Sort A,Sort B(以下i,j表示sort之后的下标,pos指sort之前的下标)
step2:若当前B[i]>A[j]则表示不存在B[i]<=A[j],last[i]=i(其实就是nil或0),否则移动j指针直到A[j]<B[i]且记录一个maxlast表示A[1]-A[j-1]的最大的A的pos,last[i]=maxlast,j赋为j-1
step3:处理以上之后最后扫一遍,记录一个新的A和B A值为连通块中所有数对的原A的最大值 B为连通块中所有数对的原B的和
预处理就是O(nlogn)
这样就只剩下二分和Dp了
这样就和POJ3017一样了
f[i]为前i个元素分段后最小的S值
f[i]=min(f[j]+max(A[j+1]....A[i]))条件sigma{B[j+1]+..+B[i]}<=二分的Ans
当f[n]<=lima时Ans可行否则不可行
用单调队列和堆维护
由于数据水,只用单调队列也可以过数据。
Code:未用堆 72MS
program poj3245;type som=record data,pos:longint; end; xom=record ta,tb:longint; end;var f,a,b,pos,s,last:array[0..50001]of longint; op1,op2:array[0..50001]of som; temp:array[0..50001]of xom; p,n,i,j,lc,rc,lima,head,tail,lasta,sumb,num,mid,top:longint; tmps:som;function min(q,p:longint):longint;begin if q<p then exit(q) else exit(p);end;function max(q,p:longint):longint;begin if q<p then exit(p) else exit(q);end;function dp(limb:longint):boolean;begin fillchar(f,sizeof(f),0); fillchar(pos,sizeof(pos),0); p:=0; head:=1;tail:=0; for i:=1 to n do begin while s[i]-s[p]>limb do inc(p); while (a[i]>a[pos[tail]])and(head<=tail) do dec(tail); inc(tail); pos[tail]:=i; while (s[i]-s[pos[head]-1]>limb)and(head<=tail) do inc(head); f[i]:=f[p]+a[pos[head]]; for j:=head to tail-1 do f[i]:=min(f[i],f[pos[j]]+a[pos[j+1]]); end; if f[n]>lima then exit(false) else exit(true);end;procedure qs(h,g:longint);var l,k,mid:Longint;begin l:=h;k:=g;mid:=op1[(l+k)div 2].data; repeat while op1[l].data>mid do inc(l); while op1[k].data<mid do dec(k); if l<=k then begin tmps:=op1[l]; op1[l]:=op1[k]; op1[k]:=tmps; inc(l);dec(k); end; until l>k; if l<g then qs(l,g); if h<k then qs(h,k);end;procedure sort(h,g:longint);var l,k,mid:Longint;begin l:=h;k:=g;mid:=op2[(l+k)div 2].data; repeat while op2[l].data>mid do inc(l); while op2[k].data<mid do dec(k); if l<=k then begin tmps:=op2[l]; op2[l]:=op2[k]; op2[k]:=tmps; inc(l);dec(k); end; until l>k; if l<g then sort(l,g); if h<k then sort(h,k);end;begin readln(n,lima); for i:=1 to n do begin readln(op1[i].data,op2[i].data); temp[i].ta:=op1[i].data; temp[i].tb:=op2[i].data; sumb:=sumb+op2[i].data; op1[i].pos:=i; op2[i].pos:=i; end; qs(1,n); sort(1,n); p:=1; for i:=1 to n do begin if op1[p].data<op2[i].data then continue; while (op1[p].data>=op2[i].data)and(p<=n) do begin lasta:=max(op1[p].pos,lasta); inc(p); end; dec(p); last[op2[i].pos]:=lasta; end; i:=1; while i<=n do begin inc(num); a[num]:=temp[i].ta; b[num]:=temp[i].tb; j:=i; top:=last[i]; while j<top do begin inc(j); top:=max(last[j],top); a[num]:=max(a[num],temp[j].ta); b[num]:=b[num]+temp[j].tb; end; i:=max(top,i)+1; end; lc:=0; for i:=1 to n do lc:=max(lc,b[i]-1); rc:=sumb; n:=num; for i:=1 to n do s[i]:=s[i-1]+b[i]; while lc<rc-1 do begin mid:=(lc+rc)div 2; if dp(mid) then rc:=mid else lc:=mid; end; writeln(rc);end.
- POJ3245 神题 二分+DP+单调队列+堆/线段树/平衡树
- [POJ3245] Sequence Partitioning && dp单调队列+二分
- SPOJ1748 - SEQPAR2 二分答案 DP优化 单调队列+线段树
- 线段树和单调队列优化DP
- 10.11 NOIP模拟赛 DP + 线段树 + DP + 单调队列
- 线段树和单调队列优化DP---POJ2373解题报告
- 线段树和单调队列优化DP---POJ2373解题报告
- Cut the Sequence,Sequence Partitioning,POJ3017,POJ3245,用单调队列优化的DP
- POJ-3017 Cut the Sequence(DP单调队列优化 + 平衡树)
- POJ 3017 Cut the Sequence 【DP+单调队列优化+平衡树】
- Light OJ 1084 线段树+dp or(单调队列+dp) 水题
- BZOJ 1012[jsoi2008] 最大数maxnumber 线段树(或者是单调队列+二分)
- NOIP模拟 最佳序列【二分答案+线段树(单调队列)】
- 平衡树?可并堆?线段树!
- pku 2823(单调队列、线段树)
- POJ2823:Sliding Window(单调队列||线段树)
- POJ2823 线段树OR单调队列
- poj2823--Sliding Window--线段树||单调队列
- hdu_2031_进制转换_oj也只是机器...
- ubuntun下cppcms安装
- 用DOS批处理实现FTP自动上传、下载、清理文件
- SandBox中方便、精确地选择物品
- net中通过配置WebConfig设置文件上传的属性
- POJ3245 神题 二分+DP+单调队列+堆/线段树/平衡树
- JavaBean中的<jsp:useBean>标签
- SQL语句的基本语法一
- Use cursor_sharing_exact refused to SQL variable binding
- Java 理论与实践: 正确使用 Volatile 变量
- 微软:Windows 8预览版下载量1天内突破50万
- Graphics->BitmapPixels
- SQL语句的基本语法二
- hibernate配置二级缓存出现的问题