• 四边形不等式优化dp学习笔记 [finished 1/2]


    四边形不等式学习笔记


    • 四边形不等式的定义

    摘自 lydslyd's bookbook

    定义一

    定义 w(x,y)w(x, y) 为定义在整数域的二元函数, 若对于定义域上的任何整数 abcda le b le c le d, 满足 w(a,c)+w(b,d)w(b,c)+w(a,d)w(a, c) + w(b, d) le w(b, c) + w(a, d), 则称函数 ww 满足 四边形不等式 .

    定义二

    定义 w(x,y)w(x, y) 为定义在整数域的二元函数, 若对于定义域上的任何整数 a<ba < b,
    满足 w(a+1,b+1)+w(a,b)w(a+1,b)+w(a,b+1)w(a+1, b+1) + w(a, b) le w(a+1, b) + w(a, b+1), 则称函数 ww 满足 四边形不等式 .

    简记为 交叉小于包含 , 证明略 .


    • 四边形不等式的应用

    dp()区间dp的优化 (石子合并)

    对于形如状态转移方程 F[i,j]=minik<j(F[i,k]+F[i,k+1])+w(i,j)F[i, j] = min_{i le k < j}(F[i,k] + F[i, k+1]) + w(i, j), 可以使用 四边形不等式 进行优化.

    3优化的前提有 3 个,
    1. ww 满足四边形不等式 .

    这是根本前提 .

    1. ww有区间包含单调性 : 对于任意 abcda le b le c le d, 满足 w(b,c)w(a,d)w(b, c) le w(a, d) .

    通过前提 22, 可以推导出 FF 也满足 四边形不等式, 证明略 .

    1. p[i,j]p[i, j] 表示 F[i,j]F[i, j] 的最优决策 kk, 若前 22 个前提都满足,
      则称 p[i,j]p[i, j] 满足 二维决策单调性, 对于任意的 i<ji < j, p[i,j1]p[i,j]p[i+1,j]p[i, j-1] le p[i, j] le p[i+1, j] .

    关键. 证明略 .


    """石子合并" 这道题目满足上述的所有前提, 因此可以使用 四边形不等式 优化,
    求解 F[i,j]F[i,j] 时, 不再在 [i,j)[i, j) 中对 kk 进行暴力枚举, 而是在 [p[i,j1],p[i+1,j]][p[i, j-1], p[i+1, j]] 中对 kk 进行枚举,

    时间复杂度计算: i=1Nj=i+1Np[i+1,j]p[i,j1]+1=i=1NNi+p[i+1,N]p[1,Ni]=N2sum_{i=1}^Nsum_{j=i+1}^N p[i+1, j] - p[i, j-1] + 1 = sum_{i=1}^N N-i + p[i+1, N] - p[1, N-i] = N^2 .

    特别地, p[i,i]=i,F[i,i]=0p[i, i] = i, F[i, i] = 0 .

    注意环状处理 .

    #include<bits/stdc++.h>
    #define reg register
    typedef long long ll;
    
    const int maxn = 5005;
    
    int N;
    int A[maxn];
    int p[maxn][maxn];
    
    ll sum[maxn];
    ll F[maxn][maxn];
    
    int main(){
            scanf("%d", &N);
            memset(F, 0x3f, sizeof F);
            for(reg int i = 1; i <= N; i ++) scanf("%d", &A[i]), A[i+N] = A[i];
            for(reg int i = 1; i <= N<<1; i ++) sum[i] = sum[i-1] + A[i], p[i][i] = i, F[i][i] = 0;
            for(reg int len = 2; len <= N; len ++)
                    for(reg int i = 1; i+len-1 <= N<<1; i ++){
                            int j = i+len-1;
                            for(reg int k = p[i][j-1]; k <= p[i+1][j]; k ++){
                                    ll t = F[i][k] + F[k+1][j] + sum[j] - sum[i-1];
                                    if(t < F[i][j]) F[i][j] = t, p[i][j] = k;
                            }
                    }
            ll Ans = F[0][0];
            for(reg int i = 1; i <= N; i ++) Ans = std::min(Ans, F[i][i+N-1]);
            printf("%lld
    ", Ans);
            return 0;
    }
    

    • 小例题

    IOI2000 邮局 .


    线dp()线性dp的优化 (待填坑)

  • 相关阅读:
    CCF NOI1006 捡石头
    POJ NOI MATH-7648 蓄水池水管问题
    CCF NOI1005 存款收益
    CCF NOI1004 填充矩形
    CCF NOI1003 猜数游戏
    CCF NOI1002 三角形
    Project Euler Problem 26 Reciprocal cycles
    HDU1799 循环多少次?
    CCF NOI1001 温度转换
    POJ NOI MATH-7647 余数相同问题
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822472.html
Copyright © 2020-2023  润新知