鱼香rose'Blog

Codeforces Round 943 (Div

\(\Huge{Codeforces~Round~943~(Div.3)F.Equal~XOR~Segments}\)

题意

给出一个长度为\(n\)的数组,然后有\(m\)次询问,每次询问区间\([l,r]\)是否是有趣的。

  • 有趣的定义:将区间分为\(k\)\((1<k)\),使得每段的异或值相等。

思路

区间异或值我们可以通过预处理来解决,\(b_i=b_{i-1}⊕a_i~,~a_{l}⊕a_{l+1}...a_r=b_r⊕b_{l-1}\)

重点就是如何判断区间是否可以分段。

如果区间有趣,那么分成的k段异或值相等。

\[\left\{\begin{array}{l} x \oplus x=0 \\ x \oplus 0=x \end{array} \Rightarrow x \oplus x \oplus x \oplus=x\right. \]

  • 若k为偶数,那么我们可以按照上面异或的性质合并,那么会发现区间异或值为0。
  • 若k为奇数,那么我们可以将k段合并为三段:\(0~x~0\)的形式,即一三段为\(0\),第二段可以为任意值。
    • 容易证明,当为奇数时,只有这种合并方式可以逆推出区间是否有趣。

标程

void Solved() { 
    int n, m; cin >> n >> m;
    vector<int> v(n + 1);
    map<int, vector<int>> mp;
    mp[0].push_back(0);
    for(int i = 1; i <= n; i ++ ) {
        int x; cin >> x;
        v[i] = x ^ v[i - 1];	//算一下异或前缀和
        mp[v[i]].push_back(i);	//将可以得到这个结果的下标放一起
    }
    while(m -- ) {
        int l, r; cin >> l >> r;
        if(v[l - 1] == v[r]) {	//k为偶数或k为奇数且x=0
            cout << "YES\n"; continue;
        }
        auto &it1 = mp[v[l - 1]];
        int p1 = *--lower_bound(it1.begin(), it1.end(), r);	//找小于等于r的第一个数
        auto &it2 = mp[v[r]];
        int p2 = *lower_bound(it2.begin(), it2.end(), l);	//找大于等于l的第一个数
        cout << (p1 > p2 ? "YES" : "NO") << '\n';
    }
    cout << endl;
}
posted @ 2026-01-15 21:52  鱼香_rose  阅读(0)  评论(0)    收藏  举报