BZOJ[1367][Baltic2004]Sequence 可并堆
2017-08-19 19:13
537 查看
题目链接http://www.lydsy.com/JudgeOnline/problem.php?id=1367
Description
Input
Output
一个整数R
Sample Input
7
9
4
8
20
14
15
18
Sample Output
13
HINT
所求的Z序列为6,7,8,13,14,15,18.
R=13
先考虑两种特殊情况:
①若t1<t2<t3<…<tn
则对于每一个zi=ti,此时最小R为0
②若t1>t2>t3>…>tn
则对于每一个zi=(t1…tn)的中位数,此时R最小,
下面是我瞎证明的过程:
对于情况②,我们对每一个zi取中位数(红色部分),则R为这些绿色部分
如改变所取的值(如图,取较大于中位数的数),则会发现前面的数减少了棕色部分,后面的数减小了紫色部分,发现这两部分事实上是相等的,前后的总和并没有改变,但R值却多了中间的那一部分(画圈部分),得证,偶数情况与其类似,在此不做赘述
我们可以将原序列分割成许多单调递减的序列,这些序列所有数都取他们的中位数
但是我们要求的是上升序列而不是不下降序列,所以需要将输入的ti处理成ti−i
首先我们把ak+1作为一个新区间直接加入队尾,令wm+1=ak+1,然后不断检查队尾两个区间的中位数wm和wm+1,如果wm>wm+1,我们需要将最后两个区间合并,并找出新区间的最优解(也就是序列a中,下标在这个新区间内的各项的中位数)。重复这个合并过程,直至w1≤w2≤…≤wm时结束,然后继续处理下一个数。
代码如下:
附:不同可并堆的效率比较:
从上到下:斜堆,左偏树,随机堆(19260817)
左偏树还是稳定啊(笑)
Description
Input
Output
一个整数R
Sample Input
7
9
4
8
20
14
15
18
Sample Output
13
HINT
所求的Z序列为6,7,8,13,14,15,18.
R=13
先考虑两种特殊情况:
①若t1<t2<t3<…<tn
则对于每一个zi=ti,此时最小R为0
②若t1>t2>t3>…>tn
则对于每一个zi=(t1…tn)的中位数,此时R最小,
下面是我瞎证明的过程:
对于情况②,我们对每一个zi取中位数(红色部分),则R为这些绿色部分
如改变所取的值(如图,取较大于中位数的数),则会发现前面的数减少了棕色部分,后面的数减小了紫色部分,发现这两部分事实上是相等的,前后的总和并没有改变,但R值却多了中间的那一部分(画圈部分),得证,偶数情况与其类似,在此不做赘述
我们可以将原序列分割成许多单调递减的序列,这些序列所有数都取他们的中位数
但是我们要求的是上升序列而不是不下降序列,所以需要将输入的ti处理成ti−i
首先我们把ak+1作为一个新区间直接加入队尾,令wm+1=ak+1,然后不断检查队尾两个区间的中位数wm和wm+1,如果wm>wm+1,我们需要将最后两个区间合并,并找出新区间的最优解(也就是序列a中,下标在这个新区间内的各项的中位数)。重复这个合并过程,直至w1≤w2≤…≤wm时结束,然后继续处理下一个数。
代码如下:
#include<algorithm> #include<cstdlib> #include<cstdio> #define N 1000600 using namespace std; int size ,ch [2],a ,root ,l ,r ,tot ,top,n; long long ans=0ll; int merge(int x,int y){ if(!x) return y;if(!y) return x; if(a[x]<a[y]) swap(x,y); ch[x][1]=merge(ch[x][1],y); size[x]=size[ch[x][1]]+size[ch[x][0]]+1; swap(ch[x][0],ch[x][1]); return x; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",a+i),a[i]-=i;//要求单调递增 for(int i=1;i<=n;i++){//root:这段区间的中位数 l[++top]=r[top]=root[top]=i;//l:这段区间包含的最左边的点,r:这段区间包含的最右边的点 tot[top]=size[i]=1;//tot:这个区间包含多少个数 size: while(top>1&&a[root[top-1]]>a[root[top]]){ r[--top]=r[top+1]; tot[top]+=tot[top+1]; root[top]=merge(root[top],root[top+1]);//将这个点合并到上一个序列里 //下面的过程是将中位数调到堆顶(不断删除堆顶) while(size[root[top]]*2>tot[top]+1) root[top]=merge(ch[root[top]][0],ch[root[top]][1]); } } for(int i=1;i<=top;i++) for(int j=l[i];j<=r[i];j++) ans+=(long long)abs(a[j]-a[root[i]]); return printf("%lld",ans),0; }
附:不同可并堆的效率比较:
从上到下:斜堆,左偏树,随机堆(19260817)
左偏树还是稳定啊(笑)
相关文章推荐
- BZOJ 1367 [Baltic2004]sequence【脑洞+可并堆
- BZOJ 1367([Baltic2004]sequence-左偏树+中位数贪心)
- 【bzoj1367】[Baltic2004]sequence 可并堆
- bzoj 1367: [Baltic2004]sequence
- [BZOJ1367] [Baltic2004]sequence
- 【BZOJ】1367: [Baltic2004]sequence
- [可并堆 中位数] BZOJ 1367 [Baltic2004]sequence
- 【BZOJ 1367】 [Baltic2004]sequence 可并堆
- BZOJ 1367 [Baltic2004]sequence 可并堆
- 【左偏树+贪心】BZOJ1367-[Baltic2004]sequence
- bzoj1367: [Baltic2004]sequence
- BZOJ 1367([Baltic2004]sequence-左偏树+中位数贪心)
- BZOJ_1367_[Baltic2004]sequence_结论题+可并堆
- 【BZOJ 1367】 [Baltic2004]sequence
- BZOJ 1367([Baltic2004]sequence-左偏树+中位数贪心)
- BZOJ 1367: [Baltic2004]sequence
- BZOJ1367 [Baltic2004]sequence 【左偏树】
- BZOJ 1367 [Baltic2004]sequence
- 【可并堆】BZOJ1367(Baltic2004)[sequence]题解
- BZOJ 1367: [Baltic2004]sequence