标签:lin 维护 结束 不同的 span math 必须 class 个数
题意:给一个序列,然后问有多少种方法能够把这个序列分成多块使得每一块的亦或和都相同。
思路:首先这种亦或和相同的题肯定要做前缀亦或和辣~
然后我们可以看如果我们选了一些分界点,会发生什么。
首先每一个分界点肯定要么是\(0\)要么是\(x\),即每一段的亦或和。
并且\(0\)和\(x\)总是间隔出现的。
所以我们就可以想到\(dp\)的状态:
\(dp(i)\)表示现在要求以\(i\)这位为结束的答案。
那么我们转移的时候找到所有在它之前的与他前缀亦或和相同的数们,加上它们的\(dp\)值乘上它们中间\(0\)的个数。
那么这样是\(O(n^2)\)的,肯定TLE。
下面考虑优化。
首先我们觉得肯定可以把每一个不同的亦或前缀和单独\(dp\)。
(因为每一个数的\(dp\)值不会转移到另外一个上面
那么就可以通过维护之前所有的\(dp\)值的和以及之前所有\(dp\)值对当前\(dp\)值的贡献来做到。
当前的\(dp\)值就是之前所有的贡献\(+1\)。
然后这个\(dp\)值加入所有\(dp\)值的和,以及所有\(dp\)值的贡献在走过一个或几个\(0\)所分割的段时需要加上经过的\(0\)的数量。
这样就可以了。在\(dp\)的时候注意判断最后一个亦或前缀和(即所有数的亦或值)不是\(0\)的情况,这代表了我们必须取最后一个的\(dp\)值。(我就在这里栽了好久
KrK:
首先把每个数出现位置放到vector中,然后开始dp:
考虑dp[i]表示到了第i位置,现在末尾就是a[i]的答案。
那么我们转移的时候是找到所有a[j]=a[i]的j,dp[i]加上dp[j]*(ij中间的0个数)。
所以我们就可以通过(现在的0个数)-(j时前面的0个数)来表示ij中间的0个数。
所以设add1、add2两个数组表示所有可以转移到i的dp值的和,所有可以转移到i的dp值乘上当时0的个数的和。
这样用add1乘上现在0的个数减去add2就是dp值了。
最后需要特判一下a[n]=0的情况,因为那时候只可以用最后一个位置的dp值,并且不能加上0的2^(n-1)的答案。
yutaka:
吐槽:这个变量名为什么要叫odd和even啊。。。
其实只是我们对于每一个数来处理dp,
然后就用odd表示所有dp值的和,even表示所有dp值乘上会给当前这个数造成的贡献的和。
那么最后就是答案如果a[n]=0就加上odd,否则加上even辣。
其实和KrK差不太多吧。
【Atcoder diverta2019 E】XOR Partitioning
标签:lin 维护 结束 不同的 span math 必须 class 个数
原文地址:https://www.cnblogs.com/denverjin/p/10853999.html