LCS 01. 下载插件(数学计算推导过程)

51 阅读1分钟

Problem: LCS 01. 下载插件

文章中存在些许公式,建议 PC 端打开观感更佳

思路

通过计算方程一阶导数、二阶导数,以及向上取整的离散性质进行分析

解题过程

  1. 问题分析+方程推导
    • 插件总数为 正整数nn ,限制范围1<=n<=1051 <= n <= 10^5

    • 假设我们最优解选择mm次用来将带宽加倍, mm为非负整数

    • 我们将问题拆分为 提速,下载 交错并以下载结束的场景

    • 我们使用aia_i表示提速的次数,bib_i表示下载的数量,使用FmF_{m}表示最优解,使用fkf_{k}表示有kk组交错场景的耗时

    • 假设只有11组时:a0=m,b0=na_0=m, b_0=n,可以得出:

      Fm=f1=m+n2mF_m=f_{1}=m+\frac {n} {2^m}
    • 假设有22组时:[a0,b0][a1,b1][a_0, b_0]、[a_1, b_1],可以得出:

      f2=a0+b02a0+a1+b12a0+a1f_{2}=a_0+\frac {b_0} {2^{a_0}}+a_1+\frac {b_1} {2^{a_0+a_1}}
      • 其中a0+a1=ma_0+a_1=mb0+b1=nb_0+b_1=n
      • 带入公式可以得出:
        f2=a0+a1+b02a0+nb02mf2=m+b02a0+nb02mf2=m+n2m+b02a0b02mf2=f1+b02a0b02mf1\begin{align} f_{2} & =a_0+a_1+\frac {b_0} {2^{a_0}}+\frac {n-b_0} {2^{m}}\\ f_{2} & =m+\frac {b_0} {2^{a_0}}+\frac {n-b_0} {2^{m}}\\ f_{2} & =m+\frac {n} {2^{m}}+\frac {b_0} {2^{a_0}}-\frac {b_0} {2^{m}}\\ f_{2} & =f_1+\frac {b_0} {2^{a_0}}-\frac {b_0} {2^{m}}\geq f_1\\ \end{align}
      • 仅当b0=0  a0=mb_0=0\ ||\ a_0=mf2=f1f_2=f_1成立,其中b0=0b_0=0表示a0a_0a1a_1连续中间不存在下载部分,a0=ma_0=m表示不能存在后续[a1,b1][a_1, b_1]部分,这两种条件均表示,一组较两组更优
      • 所以存在两组合法的 提速,下载 场景则一定不是最优解。
    • 以此类推,我们可以得出最优解:

      Fm=m+n2mF_m=m+\frac {n} {2^m}
    • 而根据题目描述可知,最后一次下载并不是完全可以利用网速,即

      nmod2m0n\bmod2^m\not=0
    • 所以可以得出 (公式1)

      Fm=m+n2m=m+n2m\begin{align} F_m&=m+\lceil\frac {n} {2^m}\rceil\\ &=\lceil m+\frac {n} {2^m}\rceil\\ \end{align}
  2. 对于 (公式1),由于包含取整函数.\lceil.\rceil,直接分析其极小值较为复杂,我们将其拆分为两部分:gm=m+n2m, Fm=gmg_m=m+\frac {n} {2^m},\ F_m=\lceil g_m\rceil
    • 先计算gmg_m的一阶导数以计算极值
      • 计算一阶导数
        • gmg_m转为指数形式:gm=m+n2mg_m=m+{n}\cdot{2^{-m}}
        • mm部分进行求导:
          ddm(m)=1\frac {d} {dm}(m)=1
        • n2m{n}\cdot{2^{-m}}部分进行求导:
          ddm(n2m)=n(ddm(2m))=n(2m ln 2ddm(m))=n ln 22m\begin{align} \frac {d} {dm}({n}\cdot{2^{-m}})&=n\cdot(\frac {d} {dm}({2^{-m}})) \\ &=n\cdot(2^{-m}\ ln\ 2\cdot\frac {d} {dm}(-m)) \\ &=-n\ ln\ 2\cdot2^{-m} \\ \end{align}
        • 所以gm=1n ln 212mg'_m=1-n\ ln\ 2\cdot \frac{1}{2^m}
      • 确定极值
        • gm=0g'_m=0,即1n ln 212m=01-n\ ln\ 2\cdot \frac{1}{2^m}=0
        • 可以求出m=log2(n ln 2)m^*=log_2(n\ ln\ 2)
    • 再计算gmg_m的二阶导数以计算极小值
      • 求二阶导数
        gm=ddm(1n ln 22m)=n ln 2(2m ln 2ddm(m))=n(ln 2)22m\begin{align} g''_m&=\frac {d} {dm}(1-n\ ln\ 2\cdot 2^{-m})\\ &= -n\ ln\ 2\cdot(2^{-m}\ ln\ 2\cdot\frac {d} {dm}(-m))\\ &= n(ln\ 2)^2\cdot2^{-m} \\ \end{align}
      • 根据二阶导数得知gm>0g''_m>0,所以gmg_m是严格凸的
      • 所以m=log2(n ln 2)m^*=log_2(n\ ln\ 2)是最小值点
    • 再根据离散性质确定FmF_m的最小值
      • 由于FmF_mgmg_m的取整函数,所以其最小值必定出现在mm^*附近
      • 所以 (公式2) 为:
        m=log2(n ln 2)m1=mm2=mFmin=min(Fm1,Fm2)\begin{align} &m^*=log_2(n\ ln\ 2)\\ &m_1= \lfloor m^* \rfloor\\ &m_2= \lceil m^* \rceil\\ &F_{min}=min(F_{m_1}, F_{m_2}) \end{align}

复杂度

使用 (公式1) 计算

  • 时间复杂度: O(log n)O(log\ n)
  • 空间复杂度: O(1)O(1)
/**
 * @param {number} n
 * @return {number}
 */
var leastMinutes = function (n) {
    // 假设f(m)表示宽带加倍m次下载n个插件需要的时间
    // f(m) = m + ceil(n / 2^m),0 <= m <= (n>>m=0)
    let m = 0;
    let min = Infinity;
    while (n >> m) {
        min = Math.min(min, m + Math.ceil(n / (1 << m)));
        m++;
    }
    return min;
};

使用 (公式2) 计算

  • 时间复杂度: O(1)O(1)
  • 空间复杂度: O(1)O(1)
/**
 * @param {number} n
 * @return {number}
 */
var leastMinutes = function (n) {
    let m = Math.log2(n * Math.LN2);
    if (m < 0) m = 0; // m >= 0
    const l = Math.floor(m);
    const r = Math.ceil(m);

    return Math.min(
        l + Math.ceil(n / (1 << l)), 
        r + Math.ceil(n / (1 << r))
    );
};