• 浅谈算法——线性基


    线性基是竞赛中常用来解决子集异或一类题目的算法。(摘自百度百科)


    线性基是一个整数序列的特殊集合,每个序列都至少存在一个线性基,同一个序列可以拥有多个不同的线性基;反过来,一个线性基只对应一个确定的序列。

    线性基存在如下三条性质

    • 原序列中任意一个数都可以由若干个线性基内的数异或得到
    • 线性基内的数无法异或得到0
    • 线性基内没有重复元素,在保证性质一的前提下,线性基内的元素个数是最少的

    在证明性质之前,首先看一下线性基的一种可行的构造法,基于这种构造法,能够保证线性基的三条性质

    const int N=50;
    ll A[N+10];
    void Add(ll x){
    	for (int i=N;~i;i--){
    		if (x&(1ll<<i)){
    			if (A[i])	x^=A[i];
    			else{
    				A[i]=x;
    				break;
    			}
    		}
    	}
    }
    

    根据其构造方法,我们可以得出(A)数组的一个性质,若(A[i])不为0,则(A[i]_{(2)})的第(i+1)位必定为1,且(A[i]_{(2)})的最高位即为第(i+1)位(证明略)

    然后,我们来对其性质进行证明

    性质一

    对于一个数(x),它仅存在两种结果,即成功插入线性基或者失败。分情况进行讨论:

    如果(x)不能插入线性基,那么(x)在最后必然变成了0,则有(xotimes A[K_1]otimes A[K_2]otimes...otimes A[K_p]=0)(otimes)表示异或),那么则有(A[K_1]otimes A[K_2]otimes...otimes A[K_p]=x),满足性质一

    如果(x)插入了线性基,记(x)插入的位置为(i),则有(xotimes A[K_1]otimes A[K_2]otimes...otimes A[K_p]=A[K_i]),那么则有(A[K_1]otimes A[K_2]otimes...otimes A[K_p]otimes A[K_i]=x),同样满足性质一

    性质二

    其实蛮显然的……如果存在(A[K_1]otimes A[K_2]otimes...otimes A[K_p]=0),那么就有(A[K_1]otimes A[K_2]otimes...otimes A[K_{p-1}]=A[K_p]),与构造方法矛盾,故假设不成立,性质二证毕

    性质三

    根据构造方法可得,线性基内不可能存在重复元素;我们也可以知道,线性基内元素增加,当且仅当序列中的新元素(x)无法被原线性基中的元素表达,除此之外,线性基内不会增加新的元素,那么性质三证毕


    然后,关于线性基的一些简单应用

    求最大值

    具体而言,求一个序列中,若干个数异或和的最大值

    首先构造这个序列的线性基,由于(A)数组的性质——即(A[i]_{(2)})的最高位必然是1,我们只需要从最高位开始贪心取数即可

    for (int i=N;~i;i--)	if ((Ans^A[i])>Ans)	Ans^=A[i];
    

    求最小值

    如果是一个序列异或和最小值,判断是否存在元素不能插入线性基,如果有,则答案为0,否则,答案与线性基内异或和最小值相同,即为最小的(A[i])

    求第K小的值

    具体而言,求一个序列,若干个数异或和的第K小值

    首先对线性基进行处理,对于一个(A[i]_{(2)}),若其第(j)位为1,则(A[i]=A[i]otimes A[j-1]),这样处理后,线性基依旧对应同一个序列,即处理前与处理后的线性基为同一序列的不同线性基,证明略

    处理完后,线性基内的元素大致如下(已转成二进制,x表示0或1)

    1x0xx0x0
      1xx0x0
         1x0
           1
    

    (K_{(2)})的第(x)位为1,则(Ans=Ansotimes A[B_x]),记(A)数组中非零元素个数为(n),则(B)数组满足(A[B_1]>A[B_2]>...>A[B_n]>0)

    ll k_th(int k){
        ll Ans=0;
        for (int i=0;i<=N;i++){
            if (A[i]){
                if (k&1)	Ans^=A[i];
                k>>=1;
            }
        }
    }
    

    特殊情况请自行处理(如K=0或K=1等)

    证明?在更改完线性基后,(A[B_x])的作用为提供其最高位的1,故按(K_{(2)})中1的位置,来对应相应的(A[B_x]),答案即为第K小的(具体过程略)

    判断一个数能否被线性基中的数异或得到

    构造函数添加返回值即可

    删除

    咕咕咕,之后填坑


    模板题:P3812 【模板】线性基

    Description
    给定n个整数(数字可能重复),求在这些数中选取任意个,使得他们的异或和最大。

    Input
    第一行一个数n,表示元素个数
    接下来一行n个数

    Output
    仅一行,表示答案。

    Sample Input
    2
    1 1

    Sample Output
    1

    HINT
    (1leqslant nleqslant 50,0leqslant S_ileqslant 2^{50})


    /*program from Wolfycz*/
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    inline char gc(){
    	static char buf[1000000],*p1=buf,*p2=buf;
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
    }
    template<typename T>inline T frd(T x){
    	int f=1; char ch=gc();
    	for (;ch<'0'||ch>'9';ch=gc())	if (ch=='-')    f=-1;
    	for (;ch>='0'&&ch<='9';ch=gc())	x=(x<<1)+(x<<3)+ch-'0';
    	return x*f;
    }
    template<typename T>inline T read(T x){
    	int f=1;char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x<0)    putchar('-'),x=-x;
    	if (x>9)	print(x/10);
    	putchar(x%10+'0');
    }
    template<typename T>inline T min(T x,T y){return x<y?x:y;}
    template<typename T>inline T max(T x,T y){return x>y?x:y;}
    template<typename T>inline T Swap(T &x,T &y){T t=x; x=y,y=t;}
    const int N=50;
    ll A[N+10];
    void Add(ll x){
    	for (int i=N;~i;i--){
    		if (x&(1ll<<i)){
    			if (A[i])	x^=A[i];
    			else{
    				A[i]=x;
    				break;
    			}
    		}
    	}
    }
    int main(){
    	int n=read(0); ll Ans=0;
    	for (int i=1;i<=n;i++)	Add(read(0ll));
    	for (int i=N;~i;i--)	if ((Ans^A[i])>Ans)	Ans^=A[i];
    	printf("%lld
    ",Ans);
    	return 0;
    }
    
  • 相关阅读:
    HDU 1061
    HDU 1028
    HDU 2191
    POJ 2249
    html.day01
    移动Web开发技巧
    chrome浏览的下载扩展程序
    webApp禁止用户保存图像
    弹出层easydialog-v2.0
    免写前缀JS包--prefixfree.min.js--插件
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/13688128.html
Copyright © 2020-2023  润新知