Xor Submatrix(Trie树)

本文介绍了一种解决最大子矩阵异或和问题的方法。通过分析异或特性和使用Trie树来高效处理子矩阵的异或和计算,实现O(n*n*logn)的时间复杂度。

Xor Submatrix

Time limit: 2000 ms
Memory limit: 512 MB

Given an array VV of size NN and another array UU of size MM, we build a matrix AA of size N \times MN×M, where A_{i, j} = V_i\ \text{xor}\ U_jAi,j=Vi xor Uj.

We say the score of a submatrix of AA is the xor sum of all its elements. Find the submatrix with the highest score.

Standard input

The first line contains two integers NN and MM.

The second line contains NN integers representing the elements of VV.

The thirst line contains MM integers representing the elements of UU.

Standard output

Print the highest possible score on the first line.

Constraints and notes

  • 1 \leq N, M \leq 10001N,M1000 
  • 0 \leq V_i < 2^{29}0Vi<229 
  • 0 \leq U_i < 2^{29}0Ui<229 
InputOutputExplanation
3 4
5 3 1
2 1 2 4
7

3 3
10 12 4
5 10 9
15

3 3
1 2 1
4 2 8
15


题意:给你两个序列V跟U,构造一个矩阵A,其中Aij = Ui ^ Vj

求最大的子矩阵的异或和。

思路:根据异或的特性,很容易想到跟奇偶有关,所以可以将子矩阵分成四种情况讨论:


偶数 * 偶数:序列U跟V的每个数都被异或了偶数次,故结果恒为0.

偶数 * 奇数:序列V的每个数都被异或了偶数次,故只需计算计算序列U中长度为偶数的异或和情况。

奇数 * 偶数:序列U的每个数都被异或了偶数次,故只需计算计算序列V中长度为偶数的异或和情况。

奇数 * 奇数:序列U跟V中长度为奇数的所有情况的异或,这个不能暴力处理,可以先将U序列或者V

                    序列的 长度为奇数的的异或和插入到Trie树中,再分析另一个序列中长度为奇数的异或

                    和与另一序列异或得到的最大值。相当于求:一个数与一个另一个序列的最大异或和。

                    时间复杂度为O(n * n * logn) 

代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace	std;
const int maxn = 10000000;
struct Trie
{
	int next[maxn][2];
	int root;
	void init()
	{
		memset(next,-1,sizeof next);
		root = 0;
	}
	void insert(int x)
	{
		int now = 0;
		for(int i=31;i>=0;i--)
		{
			if(x&(1<<i))
			{
				if(next[now][1]>=0) now = next[now][1];
				else 
				{
					next[now][1] = ++root;
					now = next[now][1];
				}
			}
			else 
			{
				if(next[now][0]>0) now = next[now][0];
				else 
				{
					next[now][0] = ++root;
					now = next[now][0];
				}
			}
		}
	}

	int query(int x)
	{
		int res = 0,now = 0;
		for(int i=31;i>=0;i--)
		{
			int tmp = x&(1<<i);
			if(next[now][!tmp]>=0)
			{
				res |= (1<<i);
				now = next[now][!tmp];
			}
			else now = next[now][tmp];
		}
		return res;
	}
};
Trie ac;
int a[1010],b[1010];
int prea[1010],preb[1010];
int main()
{
	
	int n,m; scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) 
		scanf("%d",&a[i]),prea[i] = prea[i-1]^a[i];
	for(int i=1;i<=m;i++) 
		scanf("%d",&b[i]),preb[i] = preb[i-1]^b[i];
	int res = 0;
	for(int i=1;i<=n;i++)
		for(int j=2;i+j-1<=n;j+=2) res = max(res,prea[i+j-1]^prea[i-1]); 
	for(int i=1;i<=m;i++)
		for(int j=2;i+j-1<=m;j+=2) res = max(res,preb[i+j-1]^preb[i-1]);
	ac.init();
	for(int i=1;i<=n;i++)
		for(int j=1;i+j-1<=n;j+=2) ac.insert(prea[i+j-1]^prea[i-1]);
	for(int i=1;i<=m;i++)
		for(int j=1;i+j-1<=m;j+=2) res = max(res,ac.query(preb[i+j-1]^preb[i-1]));
	printf("%d\n",res);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值