• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
jacklee404
Never Stop!
博客园    首页    新随笔    联系   管理    订阅  订阅
NC22998-奶牛异或 (Trie树 + 前缀异或)

链接:https://ac.nowcoder.com/acm/problem/22998
来源:牛客网

题号:NC22998

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

农民约翰在喂奶牛的时候被另一个问题卡住了。他的所有N(1 <= N <= 100,000)个奶牛在他面前排成一行(按序号1..N的顺序),按照它们的社会等级排序。奶牛#1有最高的社会等级,奶牛#N最低。每个奶牛同时被指定了一个不唯一的附加值,这个数在 [0, 221 - 1] 的范围内。

帮助农民约翰找出应该从哪一头奶牛开始喂,使得从这头奶牛开始的一个连续的子序列上,奶牛的附加值的异或最大。

如果有多个这样的子序列,选择结尾的奶牛社会等级最高的。如果还不唯一,选择最短的。

输入描述:

第1行:一个单独的整数N。第2到N + 1行:N个 [0, 221 - 1] 之间的整数,代表每头奶牛的被赋予的数。第j行描述了社会等级j - 1的奶牛。

输出描述:

第 1 行: 3个空格隔开的整数,分别为:最大的异或值,序列的起始位置、终止位置。

示例1

输入

[复制](javascript:void(0)😉

5
1
0
5
4
2

输出

[复制](javascript:void(0)😉

6 4 5

说明

最大异或值为6,从第4个开始喂,到第5个结束。

4 异或 2 = 6

(100) 异或 (010) = (110)

思路

​ 对于问题我们可以转化成,求\(f[i] \oplus f[j - 1]\), 其中\(f\)为前缀异或数组,其异或表示了区间\([i, j]\)的异或值,题目要求我们维护右端点选择最小的,区间长度选择最小的。

​ 这样问题就转变为了枚举\(f[i]\)通过Trie树选择一个\(f[j-1]\)和其异或最大, 其中\(j < i\)(我们可以一边插入一边枚举,保证了插入的前缀数\(f[j-1]\)都在其前面,另外要提前插入一个0,表示从1~i的前缀异或), 对于其左端点我们可以建立一个数组记录下标,每次更新下标,保证其在最右侧,这样维护了区间最小。

​ 数组开到\(2^{21}\), 保证Trie树能够记录每一个bit位

复杂度: \(O(nlogn)\)

Code

#include <iostream>
#include <vector>
using namespace std;

const int N = 3e6;

int l, r, mx = -1, b[N];

struct trie{
	int nex[N][2], idx;
	bool exist[N];

	void insert(int x) {
		int p = 0;
		for (int i = 20; i >= 0; i --) {
			if (!nex[p][x>>i&1]) nex[p][x>>i&1] = ++idx;
			p = nex[p][x>>i&1];
		}
		exist[p] = 1;
	}

	int find(int x) {
		int p = 0, res = 0;
		for (int i = 20; i >= 0; i --) {
			if (!nex[p][!(x>>i&1)]) {
				p = nex[p][x>>i&1];
				if (x>>i&1) res += (1 << i);
			} 
			else {
				p = nex[p][!(x>>i&1)];
				if (!(x>>i&1)) res += (1<<i);
			} 
		}
		return res;
	}
};

int main() {
	trie tree;
	int n; cin >> n;
	vector<int> a(n + 1), pre(n + 1);
	tree.insert(0), b[0] = 1;
	for (int i = 1; i <= n; i ++) {
		cin >> a[i];
        
        pre[i] = pre[i - 1] ^ a[i];
        
        int res = tree.find(pre[i]);
        
		if((pre[i] ^ res) > mx) {
			l = b[res], r = i, mx = pre[i] ^ res;
		}
        
        b[pre[i]] = i + 1;
        tree.insert(pre[i]);
	}
	cout << mx << " " << l << " " << r;
}
posted on 2023-01-03 10:14  Jack404  阅读(357)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3