贡献法
考虑计算01串中每一位对答案的贡献并求和:
由于每个连续段的贡献只有1,故可设定一个连续段的贡献是由这个连续段的第一个数字造成的。那么计算某一位的贡献,就只需要让这个数字成为某个连续段的开头即可。
具体地,假设计算第位且。要计算这一位对答案的贡献,则要让这一位作为所在连续段的开头,那么这一位紧左边的连续的若干0就不能加入到当前子序列中,直到遇到 左边最近的1 或者 空。而这一位右边的任意位的选取是没有限制的,因为已经规定了贡献是开头引起的,因此紧后面即使仍有连续若干0,计算的仍是该位的贡献,没有影响。这样就可以用式子来表示每一位的贡献了:
第 位的贡献(设)式子为:
其中加1是考虑左侧无数字的情况;乘号左边为第 位左侧所有1的位置,对于任意 ,都可以作为当前子序列中最左侧的字符,那么左侧的字符就可以随意选取了(因为有隔着,就保证了不会让的贡献消失,那么左侧的任意位就没有约束);而乘号右侧对应右侧任意位也是可随意选取的。
预处理即可计算当前字符串的答案。现在考虑翻转某个字符后如何快速计算新的贡献:
由 变为 ,则这一位本身一定有影响;根据式子可知的修改不会对左侧每一位的贡献有影响(证明略),而会对右侧每一位的贡献有影响 —— 对于任意 ,时,左侧的1的数量增加了(第位的影响),而时,左侧的0的数量减少了(也是第位的影响)。因此还需要考虑后缀贡献的变化。
考虑用什么数据结构维护整个过程:计算初始式子,需要求每一位相同数字的的前缀和;而修改时考虑后缀的贡献变化,也需要维护相同数字的的后缀和。而由于涉及到修改字符,前缀和与后缀和是在动态变化的,因此树状数组是最合适的维护动态前后缀和的数据结构。具体细节见代码。
code
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验