标签:
2A的题,因为又忘开64位了……不应该啊不应该。不过我还是不明白算术上溢为什么是WA而不是RE。
这道题呢在洛谷上有一个神奇的题号2048.
思路:
我们考虑所有可能连续区间的开头下标,可以发现它们是1到n-L+1,而对于一个区间左端点x,所有可能的区间右端点是x+L-1到x+R-1(如果x+R-1>n别忘了特判)。
我们考虑一个左端点x及右端点范围[y,z],初始时显然y=x+L-1,z=x+R-1。下面,找出一个属于[y,z]的右端点t,使这一范围内[x,t]是和最大的一个区间。(设sum[i]为1-i的前缀和,可以发现sum[t]就是sum[y]到sum[z]中最大的一个,而[x,t]区间的和为sum[t]-sum[x-1])
下面我们把[x,t]区间取出来,ans←ans+sum[t]-sum[x-1],剩下来两部分新的区间:
1、左端点为x,右端点由y到(t-1)
2、左端点为x,右端点由(t+1)到z
下面重点来了:
开始时,我们考虑所有的可能,也就是左端点取遍1到n-L+1,得到(n-L+1)组如上面所说的x和[x+L-1,x+R-1]。假如我们用ST表来维护sum的最大值的话,每一组端点对答案的贡献,也就是上面讲的sum[t]-sum[x-1],以及t本身,都可以在O(1)时间内得到。这样,我们可以每次从当前所有的组中选取贡献最大的一个,更新答案,再将它“分裂”为两个,重复k次,就得到了答案。为了实现,我们可以以sum[t]-sum[x-1]这个值为关键字建立大根堆,就可以实现每次删除一个,插入两个的操作了。时间复杂度O((n+k)logn)
类似的堆的题还是不少的,不过基本都比这水,大致思路都是把所有可能放在堆里,然后不停更新。
program bzoj2006; const maxn=500010; type heappoint=record x,l,r,m:longint;s:int64; end; var n,k,ll,rr,i,tmp,size,j:longint; data:array[0..maxn] of longint; sum:array[0..maxn] of int64; st:array[0..maxn,0..20] of longint; pow:array[0..20] of longint; log:array[0..2*maxn] of longint; temp:heappoint; heap:array[0..2*maxn] of heappoint; ans:int64; procedure swap(var x,y:heappoint); var temp:heappoint; begin temp:=x; x:=y; y:=temp; end; function min(x,y:longint):longint; begin if x<y then exit(x) else exit(y); end; function findmax(l,r:longint):longint; begin if sum[st[l,log[r-l+1]]]>sum[st[r-pow[log[r-l+1]]+1,log[r-l+1]]] then exit(st[l,log[r-l+1]]) else exit(st[r-pow[log[r-l+1]]+1,log[r-l+1]]); end; procedure join(x:heappoint); var i:longint; begin inc(size); heap[size]:=x; i:=size; while (i>1)and(heap[i].s>heap[i shr 1].s) do begin swap(heap[i],heap[i shr 1]); i:=i shr 1; end; end; procedure del(x:longint); var i:longint; begin heap[x]:=heap[size]; dec(size); while x shl 1<=size do begin if x shl 1=size then i:=size else if heap[x shl 1].s>heap[x shl 1+1].s then i:=x shl 1 else i:=x shl 1+1; if heap[i].s>heap[x].s then begin swap(heap[i],heap[x]); x:=i; end else exit; end; end; begin readln(n,k,ll,rr); for i:=1 to n do readln(data[i]); sum[0]:=0; for i:=1 to n do sum[i]:=sum[i-1]+data[i]; pow[0]:=1; for i:=1 to 20 do begin pow[i]:=pow[i-1] shl 1; if pow[i]>n then break; end; for i:=1 to 20 do begin if pow[i]=0 then break; for j:=pow[i-1] to pow[i]-1 do log[j]:=i-1; end; for i:=1 to n do st[i,0]:=i; for j:=1 to 20 do begin if pow[j]>n then break; for i:=1 to n do if (i+pow[j-1])>n then st[i,j]:=st[i,j-1] else if sum[st[i,j-1]]>sum[st[i+pow[j-1],j-1]] then st[i,j]:=st[i,j-1] else st[i,j]:=st[i+pow[j-1],j-1]; end; size:=0; for i:=1 to n-ll+1 do begin temp.x:=i; temp.l:=i+ll-1; temp.r:=min(i+rr-1,n); temp.m:=findmax(temp.l,temp.r); temp.s:=sum[temp.m]-sum[i-1]; join(temp); end; ans:=0; for i:=1 to k do begin ans:=ans+heap[1].s; temp:=heap[1]; tmp:=heap[1].m; if tmp>temp.l then begin temp.r:=tmp-1; temp.m:=findmax(temp.l,tmp-1); temp.s:=sum[temp.m]-sum[temp.x-1]; join(temp); end; temp:=heap[1]; if tmp<temp.r then begin temp.l:=tmp+1; temp.m:=findmax(temp.l,temp.r); temp.s:=sum[temp.m]-sum[temp.x-1]; join(temp); end; del(1); end; writeln(ans); end.
标签:
原文地址:http://www.cnblogs.com/lkmcfj/p/5452692.html