Loading

[CF 2078F] Binary Subsequence Value Sum

前言

感觉很强, 当然必须自己推一推更好

据据检验

  • 定义操作 (约束) 和开销 / 收益, 要求最值化开销 / 收益
    • 模拟操作, 找性质
    • 将约束条件数学化
      • 方便高效维护
    • 最优化问题的瓶颈, 考虑找最优解的性质来处理
    • 逐元素处理
      • 先找到统一的构造方式
      • 直接处理
      • 推导动态规划
    • 枚举开销对应的值\((\)超过 \(x\) / 不大于 \(x\) / 长度为 \(x\)\()\) , 然后考虑对于这个值进行
      • 贪心
      • 判断合法性
        • 往往拥有单调性
    • 先找到一组简单的合法解, 然后在基础上进行调整, 使其花销更优
    • 要求一个数列的多个部分 \((\)前缀, 子串 \(\cdots\)\()\) 的成本
      • 贪心找到最优操作的构造方法, 加上优化 / 找共同点
      • 往往可以形似 \(\rm{dp}\) , 继承之前的左端点/右端点的值
        • 一般状态形似 \(f_l\) 表示以 \(l\) 开头区间的贡献, \(f_r\) 表示以 \(r\) 结尾区间的贡献等等
      • 子序列
        • 推导关于序列性质的式子 \((\)例如: \(1, 0\) 的个数\()\)
        • 子序列 \(\rm{dp}\)
          • 针对当前已经有的子序列进行插入而非根据位置选择
          • 一般分为插入之前的和新开两类
    • 跳跃 / \(\cdots\) 等建图问题
      • 考虑优化建图
  • 动一个点要求计算每一个位置的答案
    • 前后缀类拼接问题
      • 预处理前后缀, 然后拼拼拼
    • 区间包含数量问题

思路

题意

给定一个 0101
定义一个前后划分方案的花费是前半部分 11 的个数减去 00 的个数乘以后半部分 11 的个数减去 00 的个数

形式化的来讲, 设 zero(l,r)\textrm{zero}(l, r) 为区间 [l,r][l, r]00 的个数, one(l,r)\textrm{one}(l, r) 为区间 [l,r][l, r]11 的个数
那么分割点 ii 的贡献为
[one(1,i)zero(1,i)]×[one(i+1,n)zero(i+1,n)]\Big[\textrm{one}(1, i) - \textrm{zero}(1, i)\Big] \times \Big[\textrm{one}(i + 1, n) - \textrm{zero}(i + 1, n)\Big]

qq 次修改, 每次取反 0101 串的某一位
对于每次修改和初始情况, 输出当前 0101 串的所有子序列最大花费之和

先找对于确定子序列的性质
考虑子序列共有 \(cnt_1\)\(1\) , \(cnt_0\)\(0\), 不难发现在过程中, \(\Big[\textrm{one}(1, i) - \textrm{zero}(1, i)\Big]\) 可以取遍 \(0 \sim cnt_1 - cnt_0\)

不妨令 \(k = \Big[\textrm{one}(1, i) - \textrm{zero}(1, i)\Big]\) , 贡献为 \(k \times \Big(cnt_1 - cnt_0 - k\Big)\)
不难发现 \(\displaystyle k \times \Big(cnt_1 - cnt_0 - k\Big)\)\(\displaystyle k = \left\lfloor \frac{cnt_1 - cnt_0}{2} \right\rfloor\) 时取到最大值 \(\displaystyle \left\lfloor \frac{cnt_1 - cnt_0}{2} \right\rfloor \left\lceil \frac{cnt_1 - cnt_0}{2} \right\rceil\)

证明

因为 ab=(a+b)2(ab)24\displaystyle ab = \frac{(a + b)^2 - (a - b)^2}{4}
a+ba + b 一定, ab|a - b| 越小, 显然 abab 越大

因此我们只要知道了 \(cnt_0, cnt_1\) , 可以 \(\mathcal{O} (1)\) 的计算出子序列的贡献

方法 \(1\)

又发现 \(01\) 串的子序列, 本质上就是挑选一些 \(1, 0\) 组成的
因此考虑用组合意义表示

考虑当前串串有 \(cnt_1\)\(1\) , \(cnt_0\)\(0\)
发现一个有 \(c_1\)\(1\) , \(c_0\)\(0\) 的子序列, 总共有 \(\displaystyle{cnt_1 \choose c_1}{cnt_0 \choose c_0}\) 个, 也就是选取任意 \(0, 1\) 子集

问题变为

\[ \begin{align*} ans &= \sum_{c_0 = 0}^{cnt_0} \sum_{c_1 = 0}^{cnt_1} {cnt_1 \choose c_1}{cnt_0 \choose c_0} \left\lfloor \frac{c_1 - c_0}{2} \right\rfloor \left\lceil \frac{c_1 - c_0}{2} \right\rceil \end{align*} \]

然后这个似乎可以化简, 但是我不是数学牢大, 不管了

方法 \(2\)

考虑 似 \(\rm{dp}\) 做法
先对于原串处理, 不管修改

前置是对

\[\left\lfloor \frac{c_1 - c_0}{2} \right\rfloor \left\lceil \frac{c_1 - c_0}{2} \right\rceil \]

的处理, 不难发现可以按 \(c_1 - c_0\) 奇偶性分开

  • \(c_1 - c_0 = 2k\)
    \(= k^2\)
  • \(c_1 - c_0 = 2k + 1\)
    \(= k(k + 1)\)

\(f(i)\) 表示串串前 \(i\) 长度部分的子序列 \((\)不包括空序列\()\) 贡献之和
考虑 \(f(i)\) 应该怎么计算, 不难发现应该分成在之前的 \(f(i - 1)\) 中插入和新开以及直接继承之前的三种

  • 在之前的 \(f(i - 1)\) 中插入
    • 这一位为 \(1\)
      • 之前 \(c_1 - c_0 = 2k\)
        \(\displaystyle\Delta = k(k + 1) - k^2 = k = \frac{c_1 - c_0}{2}\)
      • 之前 \(c_1 - c_0 = 2k + 1\)
        \(\displaystyle\Delta = (k + 1)^2 - k(k + 1) = k + 1 = \frac{c_1 - c_0 + 1}{2}\)
    • 这一位为 \(0\)
      • 之前 \(c_1 - c_0 = 2k\)
        \(\displaystyle\Delta = k(k - 1) - k^2 = -k = -\frac{c_1 - c_0}{2}\)
      • 之前 \(c_1 - c_0 = 2k + 1\)
        \(\displaystyle\Delta = k^2 - k(k + 1) = -k = -\frac{c_1 - c_0 - 1}{2}\)
  • 新开
    • 新开一个 \(1\)
      贡献为 \(0\)
    • 新开一个 \(0\)
      贡献为 \(0\)
  • 直接继承
    即直接加上 \(f(i - 1)\)

因此我们应当维护状态:

  • 值应当表示串串前 \(i\) 长度部分的子序列 \((\)不包括空序列\()\) 贡献之和

  • 维护之前 \(c_1 - c_0 = 2k + 1\) 的数量
    发现直接可以用 \(2^{i - 1}\) 表示, 考虑一些证明
    首先需要知道的是, \(c_1 - c_0 = 2k + 1\) 仅当 \(c_1, c_0\) 奇偶性不同
    可以视作在 \(cnt_1\)\(1\) 中选择 \(c_1\)\(1\) , 在 \(cnt_0\)\(0\) 中选择 \(c_0\)\(0\)
    有如下证明

    证明

    首先,我们考虑一个大小为 nn 的集合,其子集总数为 2n2^n。我们需要证明其中大小为奇数的子集个数为 2n12^{n-1}

    方法一:二项式定理

    利用二项式定理展开 (1+x)n(1 + x)^n,当 x=1x = 1 时,得到:
    (1+1)n=k=0n(nk)=2n(1 + 1)^n = \sum_{k=0}^{n} \binom{n}{k} = 2^n
    x=1x = -1 时,得到:
    (11)n=k=0n(1)k(nk)=0(1 - 1)^n = \sum_{k=0}^{n} (-1)^k \binom{n}{k} = 0
    将这两个式子相加和相减:
    k=0n(nk)+k=0n(1)k(nk)=2偶数 k(nk)=2n\sum_{k=0}^{n} \binom{n}{k} + \sum_{k=0}^{n} (-1)^k \binom{n}{k} = 2 \sum_{\text{偶数 } k} \binom{n}{k} = 2^n
    k=0n(nk)k=0n(1)k(nk)=2奇数 k(nk)=2n\sum_{k=0}^{n} \binom{n}{k} - \sum_{k=0}^{n} (-1)^k \binom{n}{k} = 2 \sum_{\text{奇数 } k} \binom{n}{k} = 2^n
    由此可得:
    偶数 k(nk)=奇数 k(nk)=2n1\sum_{\text{偶数 } k} \binom{n}{k} = \sum_{\text{奇数 } k} \binom{n}{k} = 2^{n-1}

    方法二:数学归纳法

    基例:当 n=1n = 1 时,集合的子集为 \emptyset 和自身,其中奇数子集个数为 1,即 20=12^{0} = 1,成立。
    归纳假设:假设当 n=kn = k 时,奇数子集个数为 2k12^{k-1}
    归纳步骤:考虑 n=k+1n = k + 1 的集合,新增一个元素 aa。不包含 aa 的奇数子集有 2k12^{k-1} 个,包含 aa 的奇数子集数目等于原集合中偶数子集的数目 2k12^{k-1}。因此总数为 2k1+2k1=2k2^{k-1} + 2^{k-1} = 2^k,即 2(k+1)12^{(k+1)-1},成立。

    方法三:构造配对

    固定一个元素 aa,将子集分为包含 aa 和不包含 aa 的两类。对于不包含 aa 的子集 AA,若 A|A| 为奇数,则 A{a}A \cup \{a\} 为偶数,反之亦然。这样的配对使得每对中恰好有一个奇数和一个偶数子集,总数为 2n12^{n-1} 对,奇数子集数目为 2n12^{n-1}

    结论

    无论使用哪种方法,结果都表明大小为奇数的子集个数为 2n12^{n-1}

    由此可知选出同为奇数和同为偶数的 \(c_1, c_0\) 各有 \(2^{cnt_1 - 1} \times 2^{cnt_0 - 1}\) 种, 一共有 \(2^{cnt_1 - 1 + cnt_0 - 1 + 1} = 2^{i - 1}\) 种, 那么选出奇偶性不同的也有 \(2^{i - 1}\)
    哎好像整复杂了, 无敌
    肯定有更好的方法, 但是我是弱智啊!

  • 维护之前 \(c_1 - c_0\) 之和
    不妨设为 \(g(i)\) 这样方便转移

    • 在之前的 \(g(i - 1)\) 中插入
      • 这一位为 \(1\)
        \(\displaystyle\Delta = g(i - 1) + 2^i - 1\)
      • 这一位为 \(0\)
        \(\displaystyle\Delta = g(i - 1) - 2^i + 1\)
    • 新开
      • 新开一个 \(1\)
        贡献为 \(1\)
      • 新开一个 \(0\)
        贡献为 \(-1\)
    • 直接继承
      即直接加上 \(g(i - 1)\)

    总的来说, 可以表述成

    • 这一位为 \(1\)
      \(\displaystyle\Delta = g(i - 1) + 2^i\)
    • 这一位为 \(0\)
      \(\displaystyle\Delta = g(i - 1) - 2^i\)
    • 直接继承
      即直接加上 \(g(i - 1)\)

总的来说, 我们发现完全不是 \(\rm{dp}\) 的模样
这三个东西可以简单表示, 具体的

\(cnt\) 表示之前 \(c_1 - c_0 = 2k + 1\) 的数量
\(sum\) 之前 \(c_1 - c_0\) 之和
\(res\) 表示 \(f(i)\) 的值

  • 当前为 \(1\)

    \[ \begin{align*} \begin{cases} res \leftarrow 2res + \dfrac{sum + cnt}{2} \\ cnt \leftarrow 2cnt \\ sum \leftarrow 2(sum + cnt) \end{cases} \end{align*} \]

  • 当前为 \(0\)

    \[ \begin{align*} \begin{cases} res \leftarrow 2res - \dfrac{sum - cnt}{2} \\ cnt \leftarrow 2cnt \\ sum \leftarrow 2(sum - cnt) \end{cases} \end{align*} \]

显然用矩阵维护操作即可, 基础上做矩阵线段树

总结

特殊的性质:
每次 \(\Delta = 1, 0, -1\) , 一定可以取遍极值
一般出现在

  • 单位移动 \(\&\) 出现次数

\(01\) 串子序列可以转化成组合问题

数学上奇偶性的问题往往可以拆成 \(2k, 2k + 1\) 的问题方便表示

这种全子序列的信息往往是固定的, 方便简单递推
反而如果对子序列信息有约束, 才是 \(\rm{dp}\) 发力

posted @ 2025-03-12 17:18  Yorg  阅读(21)  评论(0)    收藏  举报