zoukankan      html  css  js  c++  java
  • [Baltic2004]sequence

    题目描述:

    给定一个序列t1,t2,...,tn ,求一个递增序列z1<z2<...<zn , 使得R=|t1z1|+|t2z2|+...+|tnzn| 的值最小。本题中,我们只需要求出这个最小的R值。

    样例输入

    7 9 4 8 20 14 15 18

    样例输出

    13

    提示

    所求的Z序列为6,7,8,13,14,15,18.

    R=13

    题解:

    考虑t1>=t2>=t3>=t4这种递减的情况,那么整个z只需取t数组的中位数即可。

    由于z是递增数列,不能全取一样的数。所以我们把t[i]-i;保证z数组就可以取一样的数了 且不会影响答案,因为t[i]-i的同时,求出来z[i]也是减了i的

    那么我们就采取分治的思想,把原数列分成m个递减区间,然后分别取中位数,使得该区间的差值尽量小.

    设X[i]为没个区间的中位数,那么如果X[i]<X[i-1]时不满足z[i]递增的题意,所以要合并,且合并后的答案会更优。(见网上的论文证明)

    以下是详细做法和证明:

    还有一个我的傻逼错误

    ldis()和rdis()没写return 居然函数没有返回值不warning,浪费了很久

    代码如下:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<cstdlib>
     7 using namespace std;
     8 const int N=1000005;
     9 typedef long long ll;
    10 ll gi()
    11 {
    12     ll str=0;char ch=getchar();
    13     while(ch>'9' || ch<'0')ch=getchar();
    14     while(ch>='0' && ch<='9')str=str*10+ch-'0',ch=getchar();
    15     return str;
    16 }
    17 struct node
    18 {
    19     int dis,size,ls,rs;ll x;
    20     node *l,*r;
    21     int ldis(){return l?l->dis:0;}
    22     int rdis(){return r?r->dis:0;}
    23 }T[N];
    24 ll a[N];node *root[N],*pos=T;
    25 ll st[N],top=0;
    26 ll ans=0;
    27 void updata(node *&R)
    28 {
    29     if(R)R->size=(R->l?R->l->size:0)+(R->r?R->r->size:0)+1;
    30 }
    31 node *merge(node *p,node *q)
    32 {
    33     if(!p||!q){return p?p:q;}
    34     if(p->x<q->x)swap(p,q);
    35     if(p->ls>q->ls)p->ls=q->ls;
    36     if(p->rs<q->rs)p->rs=q->rs;
    37     p->r=merge(p->r,q);
    38     if(p->ldis()<p->rdis())swap(p->l,p->r);
    39     p->dis=p->rdis()+1;
    40     updata(p);
    41     return p;
    42 }
    43 void Delet(int x)
    44 {
    45     node *y=root[x]; 
    46     root[x]=merge(root[x]->r,root[x]->l);
    47     root[x]->ls=y->ls;root[x]->rs=y->rs;
    48     y->l=y->r=NULL;y->size=0;
    49 }
    50 int main()
    51 {
    52     int n=gi(),k;
    53     for(int i=1;i<=n;i++){
    54         a[i]=gi()-i;
    55         pos->l=pos->r=NULL;pos->x=a[i];pos->size=1;
    56         pos->ls=pos->rs=i;
    57         root[i]=pos;pos->dis=0;
    58         pos++;
    59     }
    60     int now;
    61     st[++top]=1;
    62     for(int i=2;i<=n;i++){
    63         now=i;
    64         while(top){
    65             k=st[top];
    66             if(root[k]->x>root[now]->x){
    67                 top--;
    68                 root[k]=merge(root[now],root[k]);
    69                 while((root[k]->size<<1)>(root[k]->rs-root[k]->ls+2))Delet(k);
    70                 now=k;
    71                 if(!top){
    72                     st[++top]=now;
    73                     break;
    74                 }
    75             }
    76             else{
    77                 st[++top]=now;
    78                 break;
    79             }
    80         }
    81     }
    82     while(top){
    83         k=st[top];top--;
    84         for(int i=root[k]->ls;i<=root[k]->rs;i++)ans+=abs(root[k]->x-a[i]);
    85     }
    86     cout<<ans;
    87     return 0;
    88 }
  • 相关阅读:
    类的加载
    java经典面试题(转)
    I/O NIO 2
    【转】Impala和Hive的关系
    【转】工作站和服务器的区别
    JAVA之线程
    【转】Linux中vim的粘贴复制快捷键的使用
    【转】Zookeeper集群为什么要是单数
    【转】Impala常见错误
    hadoop命令工作常用
  • 原文地址:https://www.cnblogs.com/Yuzao/p/6840398.html
Copyright © 2011-2022 走看看