D1. Infinite Sequence (Easy Version) 【Codeforces Round 1007 (Div. 2)】

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=a1a2am=a2m+1.

定义 p = a 1 ⊕ a 2 ⊕ … ⊕ a n p = a_1 \oplus a_2 \oplus \ldots \oplus a_n p=a1a2an。当 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=a1a2am=p(an+1an+2)(an+3an+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+1an+2),(an+3an+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={ppam m 为奇数, m 为偶数.

最终,通过递归地将 m m m不断减半直到 m ≤ 2 n m \le 2n m2n,并在每一步根据奇偶性应用上述规则,即可计算 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值