D1. Infinite Sequence (Easy Version)
思路
为了方便起见,假设 n n n为奇数(如果不是,则将 n n n递增并单独处理边缘情况)。首先预先计算前 2 n 2n 2n项 a 1 , a 2 , … , a 2 n a_1, a_2, \ldots, a_{2n} a1,a2,…,a2n。对于索引不超过 2 n 2n 2n的查询,直接返回预先计算的值。
当查询的索引满足 2 m > n 2m > n 2m>n时,观察到以下关系:
a 2 m = a 1 ⊕ a 2 ⊕ … ⊕ a m = a 2 m + 1 . a_{2m} = a_1 \oplus a_2 \oplus \ldots \oplus a_m = a_{2m + 1}. a2m=a1⊕a2⊕…⊕am=a2m+1.
定义 p = a 1 ⊕ a 2 ⊕ … ⊕ a n p = a_1 \oplus a_2 \oplus \ldots \oplus a_n p=a1⊕a2⊕…⊕an。当 m > n m > n m>n时,可以将XOR和分解为:
a 2 m = a 1 ⊕ a 2 ⊕ … ⊕ a m = p ⊕ ( a n + 1 ⊕ a n + 2 ) ⊕ ( a n + 3 ⊕ a n + 4 ) ⊕ … ⊕ a m . \begin{aligned} a_{2m} &= a_1 \oplus a_2 \oplus \ldots \oplus a_m \\ &= p \oplus (a_{n + 1} \oplus a_{n + 2}) \oplus (a_{n + 3} \oplus a_{n + 4}) \oplus \ldots \oplus a_m. \end{aligned} a2m=a1⊕a2⊕…⊕am=p⊕(an+1⊕an+2)⊕(an+3⊕an+4)⊕…⊕am.
由于 n n n为奇数,配对项 ( a n + 1 ⊕ a n + 2 ) , ( a n + 3 ⊕ a n + 4 ) , … (a_{n + 1} \oplus a_{n + 2}), (a_{n + 3} \oplus a_{n + 4}), \ldots (an+1⊕an+2),(an+3⊕an+4),…会相互抵消。因此公式简化为:
a 2 m = a 2 m + 1 = { p 若 m 为奇数 , p ⊕ a m 若 m 为偶数 . a_{2m} = a_{2m + 1} = \begin{cases} p & \text{若 } m \text{ 为奇数}, \\ p \oplus a_m & \text{若 } m \text{ 为偶数}. \end{cases} a2m=a2m+1={pp⊕am若 m 为奇数,若 m 为偶数.
最终,通过递归地将 m m m不断减半直到 m ≤ 2 n m \le 2n m≤2n,并在每一步根据奇偶性应用上述规则,即可计算 a m a_m am。
总时间复杂度为: O ( n + log ( m ) ) O(n + \log(m)) O(n+log(m))。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
#define int long long
#define pb push_back
#define pii pair<int, int>
#define FU(i, a, b) for (int i = (a); i <= (b); ++i)
#define FD(i, a, b) for (int i = (a); i >= (b); --i)
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
void solve() {
int n, l, r, p;
cin >> n >> l >> r;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
vector<int> pref(n + 1);
for (int i = 1; i <= n; i++) {
pref[i] = pref[i - 1] + a[i];
}
if (n % 2 == 0) {
n++;
int cur = pref[n / 2] & 1;
a.push_back(cur);
pref.push_back(pref.back() + cur);
}
for (int i = n + 1; i <= n * 2; i++) {
a.push_back(pref[i / 2] & 1);
pref.push_back(pref[i - 1] + a[i]);
}
p = pref[n] & 1;
int ret = 0;
while (true) {
if (l <= n * 2) {
ret ^= a[l];
break;
}
ret ^= p;
if ((l / 2 - n) % 2 == 0) {
break;
}
l /= 2;
}
cout << ret << endl;
}
signed main() {
cin.tie(0)->ios::sync_with_stdio(0);
int T = 1;
cin >> T;
while (T--) {
solve();
}
return 0;
}