<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>三分搜索 on 分而治之</title>
        <link>https://www.pythoner.work/tags/%E4%B8%89%E5%88%86%E6%90%9C%E7%B4%A2/</link>
        <description>Recent content in 三分搜索 on 分而治之</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <copyright>Divide and Conquer. All rights reserved.</copyright>
        <lastBuildDate>Sun, 24 Aug 2025 13:34:00 +0800</lastBuildDate><atom:link href="https://www.pythoner.work/tags/%E4%B8%89%E5%88%86%E6%90%9C%E7%B4%A2/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>CF-2132 (Codeforces Round 1043, Div. 3) 题解</title>
        <link>https://www.pythoner.work/post/cf-2132/</link>
        <pubDate>Sun, 24 Aug 2025 13:34:00 +0800</pubDate>
        
        <guid>https://www.pythoner.work/post/cf-2132/</guid>
        <description>&lt;h2 id=&#34;2132a-homework&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://codeforces.com/contest/2132/problem/A&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;2132A. Homework&lt;/a&gt;
&lt;/h2&gt;&lt;h3 id=&#34;题意&#34;&gt;题意
&lt;/h3&gt;&lt;p&gt;有 Vlad 和 Dima 两个人，他们需要依次将字符串 $b$ 中的每个字母放到字符串 $a$ 的头或尾。其中 Vlad 会将字母放到 $a$ 的开头，Dima 会将字母放到 $a$ 的末尾。&lt;/p&gt;
&lt;p&gt;已知三个字符串，$a, b, c$，其中 $c$ 代表两人操作顺序。若 $c_i$ 为 &lt;code&gt;V&lt;/code&gt;，则第 $i$ 个字母由 Vlad 放置；若 $c_i$ 为 &lt;code&gt;D&lt;/code&gt;，则由 Dima 放置。&lt;/p&gt;
&lt;p&gt;输出 $a$ 的最终状态。&lt;/p&gt;
&lt;h3 id=&#34;题解&#34;&gt;题解
&lt;/h3&gt;&lt;p&gt;模拟即可。&lt;/p&gt;
&lt;p&gt;考虑简单的实现方式，由于添加到开头（左侧）不太方便，所以我们将添加到左侧的字符保存到另一字符串中，在所有操作结束后逆序输出。&lt;/p&gt;
&lt;h3 id=&#34;参考代码&#34;&gt;参考代码
&lt;/h3&gt;&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://codeforces.com/contest/2132/submission/334976874&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Submission #334976874&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;2132b-the-secret-number&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://codeforces.com/contest/2132/problem/B&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;2132B. The Secret Number&lt;/a&gt;
&lt;/h2&gt;&lt;h3 id=&#34;题意-1&#34;&gt;题意
&lt;/h3&gt;&lt;p&gt;对于数字 $x$，可以进行一次操作：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在 $x$ 的末尾添加至少 $1$ 个数字 $0$，赋值给 $y$。&lt;/li&gt;
&lt;li&gt;操作后的数 $n = x + y$。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;给定 $n$，求所有可能的 $x$，从小至大排序输出。&lt;/p&gt;
&lt;h3 id=&#34;题解-1&#34;&gt;题解
&lt;/h3&gt;&lt;p&gt;发现&lt;/p&gt;
&lt;p&gt;$$y = x \cdot 10^k$$&lt;/p&gt;
&lt;p&gt;其中 $k$ 是添加的 $0$ 的个数，满足 $k \in \mathbb{N}^+$。&lt;/p&gt;
&lt;p&gt;因此：&lt;/p&gt;
&lt;p&gt;$$n = x + x \cdot 10^k = x \cdot (10^k + 1)$$&lt;/p&gt;
&lt;p&gt;即对于给定的 $n$，所有可能的 $x$ 的值为：&lt;/p&gt;
&lt;p&gt;$$\frac{n}{10^k + 1} 当 k \in \mathbb{N}^+ 且 (10^k + 1) | n$$&lt;/p&gt;
&lt;h3 id=&#34;参考代码-1&#34;&gt;参考代码
&lt;/h3&gt;&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://codeforces.com/contest/2132/submission/334979970&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Submission #334979970&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Tricks: 从大到小枚举 $k$，结果的 $x$ 必定是从小到大的，省一步排序。&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&#34;2132c1-the-cunning-seller-easy-version&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://codeforces.com/contest/2132/problem/C1&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;2132C1. The Cunning Seller (easy version)&lt;/a&gt;
&lt;/h2&gt;&lt;h3 id=&#34;题意-2&#34;&gt;题意
&lt;/h3&gt;&lt;p&gt;西瓜卖家在他的每次交易中只能卖掉 $3^x$ 个西瓜，价格为 $3^{x + 1} + x \cdot 3^{x - 1}$，其中 $x$ 为非负整数。&lt;/p&gt;
&lt;p&gt;买家希望通过最少的交易次数买到 $n$ 个西瓜（不能多也不能少），输出在此情况下西瓜的总价。&lt;/p&gt;
&lt;h3 id=&#34;题解-2&#34;&gt;题解
&lt;/h3&gt;&lt;p&gt;容易发现，卖掉 $3^x$ 个西瓜，相当于在三进制下使 $n$ 的从右至左第 $x + 1$ 位减少 $1$。&lt;/p&gt;
&lt;p&gt;那么，为了获得最小的次数，对于三进制下从右至左第 $x + 1$ 位，它的值为 $y$ 时，我们需要进行 $y$ 次卖掉 $3^x$ 个西瓜的操作。&lt;/p&gt;
&lt;p&gt;代入原式，加和即可。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;预处理 $3^x$ 的值即可，没必要推价格的递推公式。&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3 id=&#34;参考代码-2&#34;&gt;参考代码
&lt;/h3&gt;&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://codeforces.com/contest/2132/submission/335129815&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Submission #335129815&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;2132c2-the-cunning-seller-hard-version&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://codeforces.com/contest/2132/problem/C2&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;2132C2. The Cunning Seller (hard version)&lt;/a&gt;
&lt;/h2&gt;&lt;h3 id=&#34;题意-3&#34;&gt;题意
&lt;/h3&gt;&lt;p&gt;西瓜卖家在他的每次交易中只能卖掉 $3^x$ 个西瓜，价格为 $3^{x + 1} + x \cdot 3^{x - 1}$，其中 $x$ 为非负整数。&lt;/p&gt;
&lt;p&gt;买家希望通过不多于 $k$ 次交易，以最小的价格购买 $n$ 个西瓜，输出此时的总价，若不能满足题目要求则输出 $-1$。&lt;/p&gt;
&lt;h3 id=&#34;题解-3&#34;&gt;题解
&lt;/h3&gt;&lt;p&gt;首先把 C1 的代码抄过来，并记录交易次数、每次交易的（西瓜数的）指数。&lt;/p&gt;
&lt;p&gt;发现 $3 \times 3^{x-1}$ 的交易总是比 $3^x$ 的交易要便宜。设当西瓜数为 $x$ 时的西瓜价格为 $f(x)$，列式计算替换 $3^x$ 的交易为 $3 \times 3^{x-1}$ 的交易所降低的总价：&lt;/p&gt;
&lt;p&gt;$$f(3^x) - 3 \cdot f(3^{x-1}) = 3^{x + 1} + x \cdot 3^{x - 1} - 3 \cdot 3^x - 3 \cdot (x - 1) \cdot 3^{x - 2}$$&lt;/p&gt;
&lt;p&gt;合并同底数幂：&lt;/p&gt;
&lt;p&gt;$$= 3^{x + 1} + x \cdot 3^{x - 1} - 3^{x + 1} - (x - 1) \cdot 3^{x - 1}$$&lt;/p&gt;
&lt;p&gt;合并同类项：&lt;/p&gt;
&lt;p&gt;$$= 3^{x - 1}$$&lt;/p&gt;
&lt;p&gt;所以当有至少 $2$ 个剩余的交易次数时，应将指数最大的交易替换掉，因为这样可以降低最多的总价。注意，当剩余的交易的指数都为 $0$ 时，就不能替换了。&lt;/p&gt;
&lt;p&gt;这样做复杂度还是太高了，怎么优化？可以考虑只记录每个指数的出现次数，然后直接批量替换交易。&lt;/p&gt;
&lt;h3 id=&#34;参考代码-3&#34;&gt;参考代码
&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;易错点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;替换次数不能是负数&lt;/li&gt;
&lt;li&gt;多组数据不要忘记 &lt;code&gt;memset&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://codeforces.com/contest/2132/submission/335139556&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Submission #335139556&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;2132d-from-1-to-infinity&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://codeforces.com/contest/2132/problem/D&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;2132D. From 1 to Infinity&lt;/a&gt;
&lt;/h2&gt;&lt;h3 id=&#34;题意-4&#34;&gt;题意
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;12345678910111213...&lt;/code&gt; 的前 $k$ 个数字之和是多少？&lt;/p&gt;
&lt;p&gt;$k \leq 10^{15}$。&lt;/p&gt;
&lt;h3 id=&#34;题解-4&#34;&gt;题解
&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;Codeforces 官方题解没读懂，于是花了一晚上自己钻研出了一个方法。&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;观察发现，一位数在数字串中占据 $1 \times 9$ 个位置，二位数占据 $2 \times 90$ 个位置，以此类推。总结可得 $l$ 位数在数字串中占据 $9l \times 10^{l - 1}$ 个位置。&lt;/p&gt;
&lt;p&gt;那么，我们通过循环地从 $k$ 中减去 $9l \times 10^{l - 1}$ 直到 $k$ 小于 $9l \times 10^{l - 1}$ ，就可以得到 $k$ 所对应的数 $n$ 的位数。&lt;/p&gt;
&lt;p&gt;接着，我们使用 $k \div l$ 来获得 $n$ 在 $l$ 位数中是第几个，再加上 $10^{l - 1}$，即为 $n$ 的值。&lt;/p&gt;
&lt;p&gt;我们已经知道了第 $k$ 位数字所对应的数 $n$，那么 $1$ 到 $n-1$ 的数字之和可以通过以下方式来求出：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;把求和区间中加入一个 $0$，变为求 $[0, n-1]$ 的数字之和，这一步不影响最终结果。&lt;/li&gt;
&lt;li&gt;我们可以给所有数字加上前导零，使其与 $n-1$ 一样长（设长度为 $l$），这一步不影响最终结果。&lt;/li&gt;
&lt;li&gt;拆分求和区间：（该步骤递归进行，$x$ 代表当前求和区间右端点）
&lt;ul&gt;
&lt;li&gt;$x$ 的第一位为 $d_1$，第一位小于 $d_1$ 的构成一组（该部分可以直接求数字和，具体方法见 &lt;a class=&#34;link&#34; href=&#34;https://www.pythoner.work/post/expectation-calculate-digit-sum/&#34; &gt;用数学期望计算区间内整数各数位的和的和&lt;/a&gt;）；&lt;/li&gt;
&lt;li&gt;第一位等于 $d_1$ 的分成两部分：
&lt;ul&gt;
&lt;li&gt;第一部分为第一位等于 $d_1$ 的数，其中每个数的第一位被直接删除（该部分进入递归循环）；&lt;/li&gt;
&lt;li&gt;第二部分为 $d_1$ 乘上第一部分包括的数的个数。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;当 $x$ 为 $k \cdot 10^{m} - 1$ 的形式或一位数时，直接求和，结束递归。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;以 $n = 345$ 为例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;求 $[0, 345]$ 的数字和：
&lt;ul&gt;
&lt;li&gt;求 $[0, 299]$ 的数字和：
&lt;ul&gt;
&lt;li&gt;共有 $300$ 个数，可得后两位数字和为 $4.5 \times 300 \times 2 = 2700$；&lt;/li&gt;
&lt;li&gt;首位在 $[0, 2]$，期望为 $1$，所以首位数字和为 $1 \times 300 = 300$；&lt;/li&gt;
&lt;li&gt;因此 $[0, 299]$ 的数字和为 $2700 + 300 = 3000$。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;求 $[0, 45]$ 的数字和：
&lt;ul&gt;
&lt;li&gt;求 $[0, 39]$ 的数字和，为 $240$。&lt;/li&gt;
&lt;li&gt;求 $[0, 5]$ 的数字和，为 $15$。&lt;/li&gt;
&lt;li&gt;$4 \times 6 = 24$。&lt;/li&gt;
&lt;li&gt;所以 $[0, 45]$ 的数字和为 $240 + 15 + 24 = 279$。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;$3 \times 46 = 138$。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以 $[0, 345]$ 的数字和为 $3000 + 279 + 138 = 3417$。&lt;/p&gt;
&lt;h3 id=&#34;参考代码-4&#34;&gt;参考代码
&lt;/h3&gt;&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://codeforces.com/contest/2132/submission/335238142&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Submission #335238142&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;2132e-arithmetics-competition&#34;&gt;&lt;a class=&#34;link&#34; href=&#34;https://codeforces.com/contest/2132/problem/E&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;2132E. Arithmetics Competition&lt;/a&gt;
&lt;/h2&gt;&lt;h3 id=&#34;题意-5&#34;&gt;题意
&lt;/h3&gt;&lt;p&gt;有两个数组 $a$ 和 $b$，$a$ 的长度为 $n$，$b$ 的长度为 $m$。&lt;/p&gt;
&lt;p&gt;给出 $q$ 次询问，每次询问包括三个数 $x, y, z$，表示在 $a$ 中至多选择 $x$ 个数，在 $b$ 中至多选择 $y$ 个数，总共选择 $z$ 个数，求选择的数字之和的最大值。&lt;/p&gt;
&lt;h3 id=&#34;题解-5&#34;&gt;题解
&lt;/h3&gt;&lt;p&gt;首先，考虑暴力解法。排序两个数组，每次询问的每次选择都选择可以选择的最大数字。&lt;/p&gt;
&lt;p&gt;显然，这样是无法通过问题的。那么，如何优化呢？&lt;/p&gt;
&lt;p&gt;我们最终在同一个数组里选择的数一定是在一个连续区间内，如果我们能计算出这个区间，那么就可以通过 $O(n)$ 前缀和预处理解决问题。&lt;/p&gt;
&lt;p&gt;设选择 $p$ 个 $a$ 中的数，总共选择 $z$ 个数（可以计算出选择 $b$ 中的元素数 $q$）时选择的数字之和的最大值为 $f(p, z)$，该值可以在 $O(1)$ 时间内计算出来。&lt;/p&gt;
&lt;p&gt;发现当 $z$ 不变时 $f$ 是一个单峰函数，于是采用三分搜索求解。&lt;/p&gt;
&lt;h3 id=&#34;参考代码-5&#34;&gt;参考代码
&lt;/h3&gt;&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://codeforces.com/contest/2132/submission/335250108&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Submission #335250108&lt;/a&gt;&lt;/p&gt;
</description>
        </item>
        
    </channel>
</rss>
