AT_diverta2019_e XOR Partitioning 题解
以下讨论,下标从
先求前缀异或和数组
例如
假设划分位置是
划分出来的每段子数组的异或和相同,等价于
这意味着
相当于从
第一种情况
如果
那么定义:
如果
其中
如果
其中
初始值
答案为
这样写每次转移是
第二种情况
本题难就难在
首先,我们可以选全为
然后来讨论交替子序列的个数。
例如
那要怎么做?
遇到
例如两个
那么,怎么知道两个
方法很多,比如在遍历的同时维护
请看代码:
package main
import("bufio";."fmt";"os")
const mod = 1_000_000_007
func main() {
in := bufio.NewReader(os.Stdin)
var n, v, xor int
// f[xor] 相当于只看前缀异或和中的 0 和 xor,求 DP
f := [1 << 20]struct{ s0, s1, pre0 int }{}
for i := range f {
f[i].s0 = 1
}
cnt0 := 1 // 前缀异或和的第一个数是 0
for Fscan(in, &n); n > 0; n-- {
Fscan(in, &v)
xor ^= v
if xor == 0 {
cnt0++
} else {
t := &f[xor]
// f[i][0] = 一堆 f[j][1] 的和 = s1,这里直接把 f[i][0] 加到 s0 中
t.s0 = (t.s0 + t.s1*(cnt0-t.pre0)) % mod
// f[i][1] = 一堆 f[j][0] 的和 = s0,这里直接把 f[i][1] 加到 s1 中
t.s1 = (t.s1 + t.s0) % mod
t.pre0 = cnt0
}
}
if xor > 0 {
// 答案 = f[n][1] = 一堆 f[j][0] 的和 = s0
// 注意不能写 f[xor].s1,因为前缀异或和的末尾如果有多个 xor,我们只能选一个
Print(f[xor].s0)
} else {
ans := pow(2, cnt0-2) // 只选 0 的方案数
for _, t := range f {
// 答案 = f[n][0] = 一堆 f[j][1] 的和 = s1
// 注意不能写 t.s0,因为前缀异或和的末尾如果有多个 0,我们只能选一个
ans += t.s1
}
Print(ans % mod)
}
}
func pow(x, n int) (res int) {
res = 1
for ; n > 0; n /= 2 {
if n%2 > 0 {
res = res * x % mod
}
x = x * x % mod
}
return
}