ABC 045/C 思考及拓展

链接:https://atcoder.jp/contests/abc045/tasks/arc061_a

给出一列长度不大于10的数字列,使用‘+’进行分割,求所有方案得到的所有数字之和。

主要有三个点:

(1)由于数值比较小,所以可以使用二进制枚举,由于之前没有用过 bitset,主要是使用bitset要注意一下 \(bitset<size\_t\ N>\),bitset定义时需要固定的值N,可以使用[]进行取值也可以直接被输出,并且从小到大与二进制表示是一样的,比如 6=011000000,不管N是多长都可以从0开始取值,在重定义时 \(a=bitset<n>(x)\),要把n,x写好。

(2)优先考虑DP,可以考虑三维 \(dp[l][k][s]\),表示前l个数字,最后一个数字由k开始,目前的和为s。 考虑到s数值范围已经爆炸了,数组要记录的状态信息过多,空间支撑不了。

(3)考虑如果扩大字符串的长度,由之前的\(length\le 10\)\(length\le 1e5/1e6?\)

观察到,每个子串\(s[i..j]\)的数值可以表示为\(s[i] * 10^{j-i} + s[i+1] * 10^{j-i-1} + ... + s[j] * 10^0\), 因此,将总和分解为每个字符 $ s[k] $ 的贡献,通过数学公式计算每个字符在所有可能分割方式中的总贡献,最终累加所有字符的贡献。每个字符 $ s[k] $ 的贡献取决于其在子串 $ s[i..j] $ 中的位置。

具体来说,字符 $ s[k] $ 在子串中的权重为 $ 10^{j-k} $,且子串的出现次数由左右分割方式的数目决定:若子串起始位置为 $ i $,则左边的分割方式数目为 $ 2^{i-1} $;若子串结束位置为 $ j $,则右边的分割方式数目为 $ 2^{n-j-2} $,字符 $ s[k] $ 的总贡献为:

\[s[k] \cdot \sum_{i=0}^k \sum_{j=k}^{n-1} 10^{j-k} \cdot \text{left}(i) \cdot \text{right}(j) \]

其中:

\[\text{left}(i) = \begin{cases} 1 & \text{if } i=0 \\ 2^{i-1} & \text{otherwise} \end{cases} \, \text{right}(j) = \begin{cases} 1 & \text{if } j = n-1 \\ 2^{n-j-2} & \text{otherwise} \end{cases} \]

整理可得:

\[\begin{split} &s[k] \cdot \sum_{i=0}^k \text{left}(i) \cdot \sum_{j=k}^{n-1} 10^{j-k}\text{right}(j)\\ &=s[k]\cdot(1+\sum_{i=1}^k 2^{i-1})\cdot (1\cdot10^{n-1-k}+2^{n-k-2}\cdot \sum_{j=k}^{n-2} 5^{j-k}) \rightarrow等比数列求和\\ &=s[k]\cdot 2^k\cdot \left( \frac{2^{n-k} \cdot (5^{n-k-1} - 1)}{16} +10^{n-k-1} \right) \end{split} \]

这样每个数字字符遍历一遍加和,即可O(n)得到最终结果。

posted @ 2025-05-08 16:33  亦可九天揽月  阅读(21)  评论(0)    收藏  举报