1. 程式人生 > >[Baltic2004]sequence

[Baltic2004]sequence

ont iostream node pre col lib getch mat oid

題目描述:

給定一個序列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 }

[Baltic2004]sequence