您的位置:首页 > 其它

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

2017-01-07 10:22 561 查看

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
,b
,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();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: