题解:CF2067F Bitwise Slides
Statement
给定长度为 \(n\) 的数组 \(a\),同时你拥有一个三元组 \((P,Q,R)\),每次定义操作如下:
-
\(P:=P \oplus a_i\)
-
\(Q:=Q \oplus a_i\)
-
\(R:=R \oplus a_i\)
显然的,最多有 \(3^n\) 次操作方法。
我们定义规则:每次操作后必须保证三元组内有两数相等。
求有多少种操作方法不违背规则,答案对 \(10^9 + 7\) 取模。
\(n \leq 2 \times 10^5\)。
Solution
异或有一个性质:\(x \oplus x = 0\),可以从这里入手。
我们记 \(p_i\) 为 \(a\) 数组的前缀异或和,我们会发现每次操作后 \(P \oplus Q \oplus R = p_i\),所以说每次三元组的状态就是:
考虑它们从何转移而来,记 \(dp_{i,x}\) 表示当前在 \(i\) 三元组中相等两数值为 \(x\) 的方案数。
首先对于 \((p_i,x,x)\),它是从 \((p_i \oplus a_i,x,x)\) 转移而来,根据异或的性质,\(p_i \oplus a_i = p_{i-1}\),所以这里 \(dp_{i,x} = dp_{i-1,x}\)。
对于另外两种,当 \(x = p_i\) 时,状态为 \((p_i,p_i,p_i)\),它可以从 \((p_{i-1},p_i,p_i),(p_i,p_{i-1},p_i),(p_i,p_i,p_{i-1})\) 任意一种转移过来,所以 \(dp_{i,x} = dp_{i-1,x}\),当 \(x = p_{i-1}\) 时,它可以从 \((p_{i-1},p_{i-1},p_{i-1})\) 转移,这样有三种方案,也可以从 \((p_{i-1},p_i,p_i),(p_i,p_{i-1},p_i),(p_i,p_i,p_{i-1})\) 共两种方案,注意到都只和 \(i-1\) 有关,滚动数组优化,所以这样一番推导下方程就有了:
最后答案即为 \(\sum\limits_{i=1}^{n}{dp_{p_i}}\)。
数组开不下用 map 映射。
Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 2e5 + 10, MOD = 1e9 + 7;
int T, n, A[MAXN], preXor[MAXN];
map <int, int> dp;
inline void Dp() {
cin >> n, dp.clear();
for (int i = 1; i <= n; i ++)
cin >> A[i], preXor[i] = preXor[i - 1] ^ A[i];
dp[0] = 1;
for (int i = 1; i <= n; i ++)
dp[preXor[i - 1]] = (dp[preXor[i - 1]] * 3 % MOD + dp[preXor[i]] * 2 % MOD) % MOD;
int Ans = 0;
for (auto [u, v] : dp)
Ans = (Ans + v) % MOD;
cout << Ans << '\n';
}
signed main() {
cin.tie (0) -> sync_with_stdio (0);
cout.tie (0) -> sync_with_stdio (0);
cin >> T;
while (T --) Dp();
return 0;
}

浙公网安备 33010602011771号