决策单调性

独自空忆成欢 提交于 2020-01-22 23:11:27

决策单调性:状态转移的最优决策点单调递增

可以用二分栈或者分治来实现

二分栈中存有三元组\((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);
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!