[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 }

 

 

 

posted @ 2017-05-11 12:40  PIPIBoss  阅读(218)  评论(0编辑  收藏  举报