Codeforces Round 943(Div.3) F.Equal XOR Segments

C o d e f o r c e s   R o u n d   943   ( D i v . 3 ) F . E q u a l   X O R   S e g m e n t s \Huge{Codeforces~Round~943~(Div.3)F.Equal~XOR~Segments} Codeforces Round 943 (Div.3)F.Equal XOR Segments

文章目录

题意

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

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

思路

区间异或值我们可以通过预处理来解决, b i = b i − 1 ⊕ a i   ,   a l ⊕ a l + 1 . . . a r = b r ⊕ b l − 1 b_i=b_{i-1}⊕a_i~,~a_{l}⊕a_{l+1}...a_r=b_r⊕b_{l-1} bi=bi1ai , alal+1...ar=brbl1

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

如果区间有趣,那么分成的k段异或值相等。
{ x ⊕ x = 0 x ⊕ 0 = x ⇒ x ⊕ x ⊕ x ⊕ = x \left\{\begin{array}{l} x \oplus x=0 \\ x \oplus 0=x \end{array} \Rightarrow x \oplus x \oplus x \oplus=x\right. {xx=0x0=xxxx=x

  • 若k为偶数,那么我们可以按照上面异或的性质合并,那么会发现区间异或值为0。
  • 若k为奇数,那么我们可以将k段合并为三段: 0   x   0 0~x~0 0 x 0的形式,即一三段为 0 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;
}
  • 24
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值