• 【知识点】四边形不等式&决策单调性


    四边形不等式:

    考虑形如$dp(i,j)=min{dp(i,k)+dp(k,j)+w(i,j)}$的dp。(若为max则把下文大小关系取反即可)

    定义:若二元函数w满足$forall a<bleq c<d,w(a,c)+w(b,d)leq w(b,c)+w(a,d)$,则称其满足四边形不等式。

    几何意义:

    以x为编号,y为自变量,$w(x,y)$为因变量,把n个$w(x)$的图像画到一个坐标系里。

    再令$g(x,y)=w(x,y)-w(x-1,y)$,则只要$forall x,g(x)$关于y递减即可。

    推论1:若$w(i,j)$满足四边形不等式且$forall a<bleq c<d,w(b,c)leq w(a,d)$(包含单调),则二元函数$dp(i,j)$也满足四边形不等式。

    推论2:定义$k(i,j)$为使$dp(i,j)$取到最值的k,则在满足引理1的条件下,有$k(i,j-1)leq k(i,j)leq k(i+1,j)$。

    两推论证明:见https://www.cnblogs.com/a1b3c7d9/p/10984353.html。

    应用:显然用引理2可以将需要$O(n^{3})$枚举k的问题变成$O(n^{2})$的。

    决策单调性:

    考虑形如$dp(i)=min{dp(j)+w(j,i)}$的dp。(max类似)

    定义:一个dp满足决策单调性的充要条件是:对于两个决策点$x<y$,若在i处y优于x,则在$[i+1,n]$处y都优于x。

    引理:若w满足四边形不等式,则dp满足决策单调性。

    证明:

    令$x<y<i<j$,其中y为i的最优决策点,则有$dp(y)+w(y,i)leq dp(x)+w(x,i)$。

    由四边形不等式,有$w(x,i)+w(y,j)leq w(y,i)+w(x,j)$。

    两式相加,消去相同项,有$dp(y)+w(y,j)leq dp(x)+w(x,j)$,于是y在j处也优于x。

    应用:

    • 单调栈/单调队列内二分维护决策单调性dp。
    • CDQ分治维护决策单调性dp。

    代码(NOI2009诗人小G):

    #include<bits/stdc++.h>
    #define maxn 100005
    #define maxm 35
    #define inf 0x7fffffff
    #define ll long double
    #define rint register int
    #define debug(x) cerr<<#x<<": "<<x<<endl
    #define fgx cerr<<"--------------"<<endl
    #define dgx cerr<<"=============="<<endl
    
    using namespace std;
    int n,L,p,G[maxn]; 
    ll S[maxn],F[maxn];
    char str[maxn][maxm];
    struct node{int id,l,r;}Q[maxn];
    
    inline int read(){
        int x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    
    inline ll pw(ll a,int b){ll r=1;while(b)r=(b&1)?r*a:r,a=a*a,b>>=1;return r;}
    inline ll getf(int a,int b){return F[b]+pw(abs(S[a]-S[b]+a-b-1-L),p);}
    inline void print(int r){
        if(!r) return; 
        int l=G[r]; print(l);
        for(int i=l+1;i<=r;i++){
            if(i>l+1) printf(" "); int m=strlen(str[i]+1);
            for(int j=1;j<=m;j++) printf("%c",str[i][j]);
        }
        printf("
    ");
    }
    
    int main(){
        //freopen("P1912_1.in","r",stdin);
        //freopen("1.out","w",stdout);
        int T=read();
        while(T--){
            n=read(),L=read(),p=read();
            for(rint i=1;i<=n;i++) 
                scanf("%s",str[i]+1),S[i]=strlen(str[i]+1)+S[i-1];
            int l=1,r=1; F[0]=0,Q[1]=(node){0,1,n};
            for(rint i=1;i<=n;i++){
                while(l<r){if(Q[l].r<i)l++;else break;}
                F[i]=getf(i,Q[l].id),G[i]=Q[l].id;
                while(l<=r){
                    if(getf(Q[r].l,Q[r].id)>getf(Q[r].l,i)) r--;
                    else{
                        //cout<<r<<endl;
                        int l1=Q[r].l,r1=Q[r].r,ans=0;
                        while(l1<=r1){
                            int mid=l1+r1>>1;
                            if(getf(mid,Q[r].id)>getf(mid,i)) ans=mid,r1=mid-1;
                            else l1=mid+1;
                        } 
                        if(ans) Q[r].r=ans-1,Q[++r]=(node){i,ans,n}; 
                        else if(Q[r].r<n){int tp=Q[r].r+1; Q[++r]=(node){i,tp,n};}
                        break;
                    }
                }/*
                for(int k=l;k<=r;k++){
                    cout<<Q[k].id<<" "<<Q[k].l<<" "<<Q[k].r<<endl;
                }
                cout<<endl;*/
            }
            if(F[n]>1e18) printf("Too hard to arrange
    ");
            else printf("%.0Lf
    ",F[n]),print(n);
            printf("--------------------
    ");
        }
        return 0;
    }
    /*
    1
    4 9 2
    brysj,
    hhrhl.
    yqqlm,
    gsycl.
    */
    诗人小G
  • 相关阅读:
    关于Vim的问题s
    突然想来说几句
    直接下载Google Play市场的APK
    编译 ijg JPEG V8 库 GIF 库
    linux下 GUI 数码相册项目 持续更新中
    nes 红白机模拟器 第8篇 USB 手柄支持
    nes 红白机模拟器 第7篇 编译使用方法
    nes 红白机模拟器 第6篇 声音支持
    使用 ALSAlib 播放 wav
    ALSA 声卡 驱动 linux 4.1.36 中变化
  • 原文地址:https://www.cnblogs.com/YSFAC/p/13363203.html
Copyright © 2020-2023  润新知