• [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 }
  • 相关阅读:
    (转)CTP: 平昨仓与平今仓,log轻轻告诉你.......
    linux上的语音识别程序
    6个可以隐藏运行bat,浏览器等程序的方法
    Android——用PagerAdapter实现View滑动效果
    Android——关于PagerAdapter的使用方法的总结(转)
    Android——浅谈HTTP中Get与Post的区别(转)
    Android——远程存储器存储:JDK方式和Volley框架的get和post
    android——字符串string(转)
    Android——事务
    Android——监听事件总结
  • 原文地址:https://www.cnblogs.com/Yuzao/p/6840398.html
Copyright © 2020-2023  润新知