【高斯消元】[SGU275]To xor or not to xor

题目大意

从N个数中选出任意个数,使XOR和最大

分析

我们贪心地思考这道题,每次,我们从最高位开始枚举答案的每一位,并且总是尝试使这一位为1,并和前面所有的方程联立求解,由于数据最大为1018,1018<260,所以最多枚举60位,每次用高斯消元的复杂度为为O(n602),然后枚举60位,复杂度为O(n603)

解法

算法1:在线高斯消元法

当然,有一种求异或方程的在线算法,新增加的方程,和前面的方程联立求解的时候只需要O(n60)的时间复杂度,,然后枚举60位,复杂度为O(n602)
如果再加上压位优化,复杂度为O(n60232)

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef unsigned int uint;
#define MAXN 100
#define D 32
const int equ=63;
int n,var,row;
LL b[MAXN+10],ans,c[MAXN+10];
unsigned int a[equ+10][4];
template<class T>
void Read(T &x){
    char c;
    while(c=getchar(),c!=EOF)
        if(c>='0'&&c<='9'){
            x=c-'0';
            while(c=getchar(),c>='0'&&c<='9')
                x=x*10+c-'0';
            ungetc(c,stdin);
            return;
        }
}
void read(){
    Read(n);
    int i,j;
    for(i=0;i<n;i++)
        Read(b[i]);
    var=n;
    for(i=1;i<=equ;i++)
        for(j=0;j<var;j++)
            a[i][j/D]|=((b[j]>>(equ-i))&1)<<(j%D);
}
void gaussian_elimination(){
    int i,j,qv1=var/D,qv2=var%D;
    for(row=1;row<=equ;row++){
        a[row][qv1]|=1<<qv2;
        for(i=0;i<var;i++)
            if(a[row][i/D]&(1<<(i%D))){
                if(!c[i]){
                    c[i]=row;
                    break;
                }
                else if(c[i])
                    for(j=0;j<4;j++)
                        a[row][j]^=a[c[i]][j];
            }
        ans<<=1;
        if(i==var&&(a[row][qv1]&(1<<qv2)))
            a[row][qv1]=0;
        else
            ans|=1;
    }
}
int main()
{
    read();
    gaussian_elimination();
    printf("%I64d",ans);
}

算法2:利用高斯约当消元法的性质

我们把刚刚的算法一的矩阵(不包括常数项)逆时针旋转90°,即每一行为一个数字,每一列为每一位。
我们发现,只要我们做高斯约当消元,就可以很容易的保证当前列的异或和为一。所以,我们做完高斯消元后,将得到的矩阵一行一行的异或起来,就能得到答案。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 100
typedef long long LL;
int n,equ,var=64,row;
LL a[MAXN+10],ans;
template<class T>
void Read(T &x){
    char c;
    while(c=getchar(),c!=EOF)
        if(c>='0'&&c<='9'){
            x=c-'0';
            while(c=getchar(),c>='0'&&c<='9')
                x=x*10+c-'0';
            ungetc(c,stdin);
            return;
        }
}
void read(){
    Read(n);
    equ=n;
    for(int i=1;i<=n;i++)
        Read(a[i]);
}
void gauss_jordan(){
    int i,col;
    for(row=col=1;row<=equ&&col<=var;row++,col++){
        if(!(a[row]>>(var-col))&1)
            for(i=row;i<=n;i++)
                if(a[i]>>(var-col)&1){
                    swap(a[i],a[row]);
                    break;
                }
        if(!(a[row]>>(var-col))&1){
            row--;
            continue;
        }
        for(i=1;i<=equ;i++)
            if(i!=row&&(a[i]>>(var-col))&1)
                a[i]^=a[row];
    }
    row--;
}
void print(){
    for(int i=1;i<=row;i++)
        ans^=a[i];
    printf("%I64d",ans);
}
int main()
{
    read();
    gauss_jordan();
    print();
}
posted @ 2016-01-31 09:15  outer_form  阅读(158)  评论(0编辑  收藏  举报