决策单调性:状态转移的最优决策点单调递增
可以用二分栈或者分治来实现
二分栈中存有三元组\((l,r,pos)\),\(l\)代表决策的作用起点,\(r\)代表决策的作用终点,\(pos\)是决策点的位置
若当前状态\(i\)已经不在栈头决策点的范围内,就弹出栈头
若位置为\(i\)的决策优于栈尾的决策,才进行下一步操作,来更新决策
若新决策点的作用范围覆盖了旧决策点,就弹出栈尾
若栈空了,就直接加入新决策点,说明其当前是最优的,否则就通过在旧决策点的范围内二分,来确定旧决策点的终点和新决策的的起点
时间复杂度\(O(n\ log\ n)\)
诗人小G:\(f_i=\min\limits_{j=0}^{i-1}\ f_j+|s_i-s_j-L-1|^P\)
\(code:\)
ld calc(int i,int j) { return f[j]+qp((ld)abs(s[i]-s[j]-l-1),p); } int find(node t,int x) { int l=t.l,r=t.r,pos=t.pos; while(l<=r) { int mid=(l+r)>>1; if(calc(mid,x)<=calc(mid,pos)) r=mid-1; else l=mid+1; } return l; } ...... q[h=t=1]=(node){1,n,0}; for(int i=1;i<=n;++i) { if(h<=t&&q[h].r<i) h++; f[i]=calc(i,q[h].pos),pre[i]=q[h].pos; if(calc(n,i)<=calc(n,q[t].pos)) { while(h<=t&&calc(q[t].l,i)<=calc(q[t].l,q[t].pos)) t--; if(h>t) q[++t]=(node){i,n,i}; else { int x=find(q[t],i); q[t].r=x-1; q[++t]=(node){x,n,i}; } } }
Lightning Conductor:\(f_i=\max\limits_{j=1}^{i-1}\ a_j-a_i+\sqrt{|i-j|}\)
二分栈写法
\(code:\)
struct node { int l,r,pos; }q[maxn]; double calc(int i,int j) { return a[j]-a[i]+sqrt(i-j); } int find(node t,int x) { int l=t.l,r=t.r,pos=t.pos; while(l<=r) { int mid=(l+r)>>1; if(calc(mid,x)>=calc(mid,pos)) r=mid-1; else l=mid+1; } return l; } void dp(double *f) { q[h=t=1]=(node){1,n,0}; for(int i=1;i<=n;++i) { if(h<=t&&q[h].r<i) h++; f[i]=calc(i,q[h].pos); if(calc(n,i)>=calc(n,q[t].pos)) { while(h<=t&&calc(q[t].l,i)>=calc(q[t].l,q[t].pos)) t--; if(h>t) q[++t]=(node){i,n,i}; else { int x=find(q[t],i); q[t].r=x-1; q[++t]=(node){x,n,i}; } } } }
分治写法
\(code:\)
ld calc(int i,int j) { return (ld)a[j]+(ld)sqrt((ld)(i-j)); } void solve(int l,int r,int L,int R,ld *f) { int x=0,mid=(l+r)>>1; for(int i=L;i<=min(mid,R);++i) { ld now=calc(mid,i); if(now>f[mid]) f[mid]=now,x=i; } f[mid]-=a[mid]; if(l<mid) solve(l,mid-1,L,x,f); if(r>mid) solve(mid+1,r,x,R,f); }
来源:https://www.cnblogs.com/lhm-/p/12229791.html