CF div4 1003(H)

H

贡献法

考虑计算01串中每一位对答案的贡献并求和:

由于每个连续段的贡献只有1,故可设定一个连续段的贡献是由这个连续段的第一个数字造成的。那么计算某一位的贡献,就只需要让这个数字成为某个连续段的开头即可。

具体地,假设计算第i位且s[i]=0。要计算这一位对答案的贡献,则要让这一位作为所在连续段的开头,那么这一位紧左边的连续的若干0就不能加入到当前子序列中,直到遇到 左边最近的1 或者 空。而这一位右边的任意位的选取是没有限制的,因为已经规定了贡献是开头引起的,因此紧后面即使仍有连续若干0,计算的仍是该位的贡献,没有影响。这样就可以用式子来表示每一位的贡献了:

i 位的贡献(设s[i]=0)式子为:

(1+j<i,s[j]=12j1)2ni

其中加1是考虑s[i]左侧无数字的情况;乘号左边为第 i 位左侧所有1的位置,对于任意 j<is[j]=1,都可以作为当前子序列中s[i]最左侧的字符,那么s[j]左侧的字符就可以随意选取了(因为有s[j]=1隔着s[i]=0,就保证了不会让s[i]的贡献消失,那么s[j]左侧的任意位就没有约束);而乘号右侧对应s[i]右侧任意位也是可随意选取的。

O(n)预处理即可计算当前字符串的答案。现在考虑翻转某个字符后如何快速计算新的贡献:

s[i]0 变为 1,则s[i]这一位本身一定有影响;根据式子可知s[i]的修改不会对s[i]左侧每一位的贡献有影响(证明略),而会对s[i]右侧每一位的贡献有影响 —— 对于任意 j[i+1,n]s[j]=0时,s[j]左侧的1的数量增加了(第i位的影响),而s[j]=1时,s[j]左侧的0的数量减少了(也是第i位的影响)。因此还需要考虑后缀贡献的变化。

考虑用什么数据结构维护整个过程:计算初始式子,需要求每一位相同数字的2j的前缀和;而修改时考虑后缀的贡献变化,也需要维护相同数字的2j的后缀和。而由于涉及到修改字符,前缀和与后缀和是在动态变化的,因此树状数组是最合适的维护动态前后缀和的数据结构。具体细节见代码。

code

posted @   jxs123  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验
主题色彩
点击右上角即可分享
微信分享提示