[Baltic2004]sequence
题目描述:
给定一个序列t1,t2,...,tn ,求一个递增序列z1<z2<...<zn , 使得R=|t1−z1|+|t2−z2|+...+|tn−zn| 的值最小。本题中,我们只需要求出这个最小的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 }