zoukankan      html  css  js  c++  java
  • 「CodeChef REBXOR」Nikitosh and xor

    Description

    给定一个长度为 (n) 的数列 (a_1,a_2,...,a_n),选定四个整数 (l_1,r_1,l_2,r_2(1le l_1le r_1<l_2le r_2le n)),则函数 (operatorname{F}(l_1,r_1,l_2,r_2)) 的计算方式如下:

    [operatorname{F}(l_1,r_1,l_2,r_2)=(a_{l_1}oplus a_{l_1+1} oplus cdots oplus a_{r_1})+(a_{l_2}oplus a_{l_2+1} oplus cdots oplus a_{r_2}) ]

    对于所有符合条件的 ((l_1,r_1,l_2,r_2)) ,求 (operatorname{F}(l_1,r_1,l_2,r_2)) 的最大值。

    Hint

    (1le nle 4 imes 10^5, a_i in [0,10^9])

    Solution

    (operatorname{lmax}(i)) 为前 (i) 个数中选取连续的某一段,得到的最大异或和是多少。对于 (operatorname{rmax}(i)) 同样定义。

    假设我们已经计算好了 (operatorname{lmax})(operatorname{rmax}) ,那么答案就是 (maxlimits_{i=1}^{n-1}{operatorname{lmax}(i)+operatorname{rmax}(i+1)})

    选现在的问题就是如何求 (operatorname{lmax})(operatorname{rmax}) 了,以 (operatorname{lmax}) 为例:

    (operatorname{pre}(i) = a_1oplus a_2oplus cdots oplus a_i)(其实就是前缀异或和)。

    那么对于 (operatorname{pre}(i)) 我们需要找一个 (i) 之前的一个前缀异或和与之异或来得到一段异或和,并且要求这个异或得到的值尽可能大。

    求最大异或和,很自然的想到 Trie 树:只要把 (operatorname{pre}(1,2,cdots ,i-1))(0) 存入 Trie 中,就可以找到这个最大异或值。

    另外,这个最大异或值还不一定比上一个优,所以还需与 (operatorname{lmax}(i)) 取最大值。

    综上: (operatorname{lmax}(i) = max(operatorname{lmax}(i-1), operatorname{query}(operatorname{pre}(i)))) ,其中 (operatorname{query}(x)) 是指在 Trie 中找到的与 (x) 的异或产生的最大值。

    同理: (operatorname{rmax}(i) = max(operatorname{rmax}(i+1), operatorname{query}(operatorname{suf}(i)))) ,其中 (operatorname{suf}) 为后缀异或和。

    时间复杂度 (O(nlog U))(U) 为值域。

    注意事项:

    1. 第二次使用 Trie 前记得清空。
    2. 计算 (operatorname{suf},operatorname{rmax}) 时记得从 (n)(1)

    Code

    /*
     * Author : _Wallace_
     * Source : https://www.cnblogs.com/-Wallace-/
     * Problem : CodeChef REBXOR Nikitosh and  xor
     */
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    
    const int N = 4e5 + 5;
    const int S = N << 6;
    
    int ch[S][2];
    int total = 1;
    
    void reset() {
    	memset(ch, 0, sizeof ch);
    	total = 1;
    }
    void insert(int val) {
    	for (register int cur = 1, i = 30; ~i; --i) {
    		int c = val >> i & 1;
    		if (!ch[cur][c]) ch[cur][c] = ++total;
    		cur = ch[cur][c];
    	}
    }
    int search(int val) {
    	int cur = 1, ret = 0;
    	for (register int i = 30; ~i; --i) {
    		int c = val >> i & 1;
    		if (ch[cur][!c]) c ^= 1, ret |= 1 << i;
    		cur = ch[cur][c];
    	}
    	return ret;
    }
    
    int ary[N], n;
    int pre[N], suf[N];
    int lmax[N], rmax[N];
    
    signed main() {
    	cin >> n;
    	for (register int i = 1; i <= n; i++)
    		cin >> ary[i];
    	
    	for (register int i = 1; i <= n; i++)
    		pre[i] = pre[i - 1] ^ ary[i];
    	for (register int i = n; i >= 1; i--)
    		suf[i] = suf[i + 1] ^ ary[i];
    	
    	reset(), insert(0);
    	for (register int i = 1; i <= n; i++)
    		lmax[i] = max(lmax[i - 1], search(pre[i])), insert(pre[i]);
    	reset(), insert(0);
    	for (register int i = n; i >= 1; i--)
    		rmax[i] = max(rmax[i + 1], search(suf[i])), insert(suf[i]);
    	
    	int ans = 0;
    	for (register int i = 1; i < n; i++)
    		ans = max(ans, lmax[i] + rmax[i + 1]);
    	cout << ans << endl;
    	return 0;
    }
    
  • 相关阅读:
    C++ 黑白棋AI minimax+alphabeta剪枝
    BZOJ2839 集合计数 容斥
    BZOJ2287 消失之物
    CF235B Let's Play Osu! 期望DP
    线性基
    [HAOI2008]糖果传递 结论题
    [HAOI2007]上升序列
    线性筛及线性递推欧拉函数
    Codeforces 1064D/1063B Labyrinth
    洛谷P2120 [ZJOI2007]仓库建设 斜率优化DP
  • 原文地址:https://www.cnblogs.com/-Wallace-/p/12676519.html
Copyright © 2011-2022 走看看