bzoj 1367: [Baltic2004]sequence

1367: [Baltic2004]sequence

Time Limit: 20 Sec  Memory Limit: 64 MB

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

详细证明请看IOI2005国家集训队论文  黄源河

https://wenku.baidu.com/view/20e9ff18964bcf84b9d57ba1.html

两个极端情况:

1、a[i]<a[i+1]<a[i+2]<a[i+3]……  ans[i]=a[i]

2、a[i]>a[i+1]>a[i+2]>a[i+3]……  ans[i]=ans[i+1]=ans[i+2]=a[i+3]=区间中位数

将每一个点看做一个区间,如果前一个区间的中位数比这个大,则合并

所以我们对于每一段已求好的序列,既要维护它的中位数,又要支持合并

因为我们合并的前提是:中位数(i)>中位数(i+1),那么对于合并后的i而言,中位数肯定是不升的

根据这个性质我们又可以用可并堆了,堆顶元素表示该序列中的中位数

当堆的元素个数*2>序列长度+1的时候就可以弹出堆顶

如何保证严格上升?

常用套路:a[i]-i

#include<cstdio>
#include<algorithm>
#define N 1000001
using namespace std;
int a[N],siz[N],tot[N],root[N],lc[N],rc[N],now,lp[N],rp[N],dis[N];
int merge(int x,int y)
{
    if(!x) return y;
    if(!y) return x;
    if(a[x]<a[y]) swap(x,y);
    rc[x]=merge(rc[x],y);
    siz[x]=siz[lc[x]]+siz[rc[x]]+1;
    if(dis[lc[x]]<dis[rc[x]]) swap(lc[x],rc[x]);
    dis[x]=dis[rc[x]]+1;
    return x;
}
int main()
{
    int n;
    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[++now]=i;
        lp[now]=rp[now]=i;
        siz[root[now]]=tot[now]=1;
        while(now>1&&a[root[now-1]]>a[root[now]])
        {
            now--;
            rp[now]=rp[now+1]; tot[now]+=tot[now+1];
            root[now]=merge(root[now],root[now+1]);
            while(siz[root[now]]*2>tot[now]+1)
              root[now]=merge(lc[root[now]],rc[root[now]]);
        }
    }
    long long ans=0;
    for(int i=1;i<=now;i++)
     for(int j=lp[i];j<=rp[i];j++)
      ans+=abs((long long)a[j]-a[root[i]]);
    printf("%lld",ans);
}
时间: 2024-08-06 03:45:41

bzoj 1367: [Baltic2004]sequence的相关文章

bzoj 1367: [Baltic2004]sequence(中位数+可并堆)

1367: [Baltic2004]sequence Time Limit: 20 Sec  Memory Limit: 64 MB Submit: 935  Solved: 351 [Submit][Status][Discuss] 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 Source [Submit]

BZOJ 1367 [Baltic2004]sequence 可并堆

题意:链接 方法:可并堆 解析: wzc讲的第二道可并堆?不这是第一道,然后之前他好像还讲了个双堆求中位数? 大概想想,是不是就是维护一个小根堆以及一个大根堆,之后每次来元素,比中位数大就加到小根堆,比中位数小就加到大根堆,之后如果两堆差超过了2,就往少的里加,之后元素多的堆里的堆顶元素是新中位数? 好像是吧我也没太听,不过自己YY这感觉像是对的? 反正我不会写堆 以上与本题无关 接下来说本题: 首先让我们这么想,如果一个递增序列,那么它的对应选取的序列就是其本身,对答案没有贡献,如果一个递减序

1367: [Baltic2004]sequence

1367: [Baltic2004]sequence Time Limit: 20 Sec  Memory Limit: 64 MB Submit: 1090  Solved: 432 [Submit][Status][Discuss] 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 Source [题解]: 详

【BZOJ 1367】 [Baltic2004]sequence

1367: [Baltic2004]sequence Time Limit: 20 Sec  Memory Limit: 64 MB Submit: 631  Solved: 215 [Submit][Status] 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 左偏树. 详细题解(在P13). 这个题解求的z

【bzoj1367】[Baltic2004]sequence

2016-05-31 17:31:26 1 #include<bits/stdc++.h> 2 #define inf 1000000000 3 #define ll long long 4 #define N 1000005 5 using namespace std; 6 int read(){ 7 int x=0,f=1;char ch=getchar(); 8 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 9 wh

BZOJ 1367

1367: [Baltic2004]sequence Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1111  Solved: 439 [Submit][Status][Discuss] Description Input Output 一个整数R Sample Input 794820141518 Sample Output 13 HINT 所求的Z序列为6,7,8,13,14,15,18.R=13 学长论文:左偏树的特点及其应用 cnt是区间标

【BZOJ1367】[Baltic2004]sequence 左偏树

[BZOJ1367][Baltic2004]sequence 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 题解:详见论文 然而本题要求z[i]严格递增,那就让所有t[i]-=i就好了 #include <cstdio> #include <cstring> #include <iostrea

sequence(bzoj 1367)

Description Input Output 一个整数R Sample Input 794820141518 Sample Output 13 HINT 所求的Z序列为6,7,8,13,14,15,18.R=13 /* 思维很扭曲(反正我想不出来)的一道题. 先想想不下降的: 考虑一个正序的序列,z[i]=t[i] 考虑一个逆序的序列,z[i]=x(x是逆列的中位数) 既然是这样那么我们就可以把整个序列化分成逆序的若干段,对于每段求中位数(正序的可看成num个逆序的). 维护中位数用左偏树,

BZOJ 3043: IncDec Sequence

3043: IncDec Sequence Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 578  Solved: 325[Submit][Status][Discuss] Description 给定一个长度为n的数列{a1,a2...an},每次可以选择一个区间[l,r],使这个区间内的数都加一或者都减一.问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种. Input 第一行一个正整数n 接