bzoj 4269: 再见Xor (高斯消元求解线性基)

4269: 再见Xor

Time Limit: 10 Sec   Memory Limit: 512 MB
Submit: 250   Solved: 148
[ Submit][ Status][ Discuss]

Description

给定N个数,你可以在这些数中任意选一些数出来,每个数可以选任意多次,试求出你能选出的数的异或和的最大值和严格次大值。

Input

第一行一个正整数N。
接下来一行N个非负整数。

Output

一行,包含两个数,最大值和次大值。

Sample Input

3
3 5 6

Sample Output

6 5

HINT

100% : N <= 100000, 保证N个数不全是0,而且在int范围内


Source

[ Submit][ Status][ Discuss]


题解:分析可得一个数选多次是无意义的,要么选一,要么不选。

那么其实问题就等价成n个数,选其中任意个异或,求最大和次大值。

我们可以用高斯消元求解线性基,会得到一个对角线为1的矩阵

10000

01000

00100

00010

00001   对角线上方可能为0,可能为1,下方一定是0. 那么每行对应的二进制数其实就组成了一组合法的基底。

因为基底中的每一个数的最高位是不同的,而且最高位单调递减,所以用基底表示出的所以数都是不同的。如果出去0的情况不考虑的话,最多会产生2^tot-1个不同的异或和。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 100003
using namespace std;
int n,m;
int a[N],b[N],tot,zero;
void gauss()
{
	tot=zero=0;
	for (int i=b[30];i;i>>=1){
		int j=tot+1;
		while (!(i&a[j])&&j<=n) j++;
		if (j==n+1) continue;
		tot++;
		swap(a[j],a[tot]);
		for (int k=1;k<=n;k++)
		 if (k!=tot&&(a[k]&i)) a[k]^=a[tot];
	}
	if (tot!=n) zero=1;
}
void solve()
{
	int mx=0;
	int t=b[tot]-1;
	for (int i=1;i<=tot;i++)
	 if (t&(b[tot-i])) mx^=a[i];
	printf("%d ",mx);
	mx=0;
	t--;
	for (int i=1;i<=tot;i++)
	 if (t&(b[tot-i])) mx^=a[i];
	 printf("%d\n",mx);
}
int main()
{
	freopen("a.in","r",stdin);
	scanf("%d",&n);
	b[0]=1;
	for (int i=1;i<=30;i++) b[i]=b[i-1]*2; 
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	gauss();
	solve();
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值