zoukankan      html  css  js  c++  java
  • 线性基

    先普及一些异或的性质:

    [egin{cases} aoplus b=boplus a\ aoplus a=0\ aoplus b=cLeftrightarrow aoplus c=bLeftrightarrow boplus c=a\ end{cases} ]

    线性基

    ( exttt{OI}) 中的线性基即异或线性基,属于一种算法或数据结构。异或线性基可以解决序列子集的异或和问题,常用于出思维题。


    定义

    对于一个序列 (a_i(1le ile n)),它的线性基为序列 (lb_j(1le jle c,c=log_2{ m max}A))(lb_j)(a_i) 的子集异或和集相等。

    (lb_j) 是序列 (a_i) 的一个子集的异或和,并且该异或和的最高位 (1)(2^j)
    如果不存在一个子集使得异或和的最高位 (1)(2^j)(lb_j=0)
    一个序列的线性基可以有很多种。

    如序列

    [a_i(1le ile 3)={10=(1010)_2,5=(101)_2,7=(111)_2} ]

    的线性基可以是

    [lb_j(0le jle 3)={0,2=(10)_2,5=(101)_2,10=(1010)_2} ]

    。其中 (lb_1=2=5oplus 7),不存在序列 (a_i) 的子集使异或和的最高位 (1)(2^0)


    操作

    插入

    线性基的构造是通过插入数 (x) 来实现的。每次插入 (Theta(log { m max}A))

    具体实现方法是逆序遍历(x)(1) 的二进制位 (j)

    如果该位有线性基(即 (lb_j ot=0)),令 (x=xoplus lb_j),以消除 (x)(j) 位,让 (x) 继续去找属于自己的一位。

    如果该位没线性基(即 (lb_j=0)),令 (lb_j=x),此时 (x) 已经异或了不少 (lb_k(j<klelog{ m max}A)) 了,他的实质是序列 (a_i) 自己的一个异或和。

    代码:

    //LB
    const int LOGA=50;
    ll lb[LOGA+7];
    void add(ll x){
    	for(int i=LOGA;i>=0;i--)if(x>>i){
    		if(lb[i]) x^=lb[i];
    		else return void(lb[i]=x);
    	}
    	//很明显,一个数可能没有插入任何位置,然后就会跑到这里
    }
    

    查询

    • 最大子集异或和

    例题:洛谷P3812 【模板】线性基

    这里的最大子集异或和既可以是序列本身的最大子集异或和,又可以是在子集异或和异或一个数 (x) 的条件下的最大异或和

    如果是前者,初始化 (res=0);如果是后者,初始化 (res=x)

    同样是逆序遍历二进制位,如果 (resoplus lb_j>res),就令 (res=resoplus lb_j)

    为什么这样的贪心思想是正确的?可以想象每一个新异或上的 (lb_j) 都是不可能覆盖之前异或了的高位的,所以这是个没有后效性的贪心,所以是正确的。

    代码:

    int findmax(int x){
    	int res=x;
    	for(int i=LOGA;i>=0;i--)if((res^lb[i])>res) res^=lb[i];
    	return res;
    }
    

    • 子集异或和是否可以等于一个数

    例题:Codeforces959F Mahmoud and Ehab and yet another xor task

    有点像反插入。逆序遍历 (x)(1) 的二进制位 (j)

    如果有线性基,就令 (x=xoplus lb_j) 以抵消 (x)(j) 位,应用了

    [xoplus lb_j=igoplus_{iin xset}ioplus a_i(lb_j=a_i,igoplus_{iin xset}i=x,xsetin a) ]

    的引理(说了好像和没说一样)。

    如果没线性基,说明子集异或和不可以等于 (x)

    代码:

    int find(int x){
    	for(int i=LOGA;i>=0;i--)if(x>>i){
    		if(lb[i]) x^=lb[i];
    		else return 0;
    	}
    	return 1;
    }
    

    • 是否有不同子集异或和相同/是否有非空子集异或和为 (0)

    例题:洛谷P5556 圣剑护符

    很明显这两个问题是同个问题,因为 (xoplus x=0)

    同插入,如果有一个元素没有插入任何位置,说明这个元素可以被另一个子集的异或和替代,说明有不同子集异或和相同/有非空子集异或和为 (0)

    代码同插入。

    附:最大权值无子集异或和为 (0) 子集

    例题:BJWC2011 元素

    即每个元素有值和权值,求一个子集,使得不存在这个子集的子集异或和为 (0),并且这个子集权值和最大。

    按权值从大到小排序,依次插入,把能插入某个线性基位置的加起来。

    代码:

    sort(&a[1],&a[n+1],cmp); int sm=0;
    for(int i=1;i<=n;i++)if(add(x(a[i]))) sm+=y(a[i]);
    printf("%d
    ",sm);	
    

    • 序列子集异或成 (x) 的方案数/序列子集可以异或成的不同异或和数

    例题:洛谷P4869 albus就是要第一个出场

    这要用一个引理:

    (k=sum_{j=0}^{{ m max}A}[lb_j ot=0])

    序列 (a{n})子集可以异或成的不同异或和数(2^k)

    对于每个异或和 (x),序列 (a{n})(2^{n-k}) 种本质不同的子集异或和为 (x) 的方案。

    对于 (x=0)(2^{n-k}) 种本质不同的方案中包括了空集

    怎么证明呢?考虑到每个非零线性基可以选或不选,所以异或和有 (2^k) 种。考虑到异或的几个灵活的性质,可以推出每个没有插入线性基的序列元素,可以选或不选,所以每个异或和 (x)(2^{n-k}) 种方案。

    异或和排名同理。

    代码:

    //Pow
    const int mod=10086;
    int Pow(int a,int x){
    	if(a==0) return 0; int res=1;
    	for(;x;(a*=a)%=mod,x>>=1)if(x&1) (res*=a)%=mod;
    	return res;
    }
    
    scanf("%d",&q);
    vector<int> in;
    for(int i=0;i<=LOGA;i++)if(lb[i]) in.pb(i);
    int pre=0;
    for(int i=0;i<sz(in);i++)if((q>>in[i])&1) (pre+=1<<i)%=mod;
    (pre*=Pow(2,n-sz(in)))%=mod;
    printf("%d
    ",(1+pre)%mod);
    

    • 无向图上最大异或路径

    例题:WC2011 最大XOR和路径

    这是线性基最玄学的操作之一。先随意生成树,对于每个环记录替换方案。具体看

    题解-[WC2011]最大XOR和路径

    吧。

    代码见题解。


    练习

    线性基的题都是思维题。
    (qquadqquadqquadqquadqquadqquadqquadqquadqquadqquadqquad)——( exttt{Segmenttree})


    洛谷P5556 圣剑护符

    树链剖分,如果两点间距离 (>30),根据抽屉原理,输出 ( exttt{YES});否则把之间的点依次插入线性基,看是否有不同子集异或和相同。代码

    CF724G Xor-matic Number of the Graph

    用了类似图上最大异或路径的玄学操作,总体是上述多个查询的合体,具体解法略。代码

    CQOI2013 新Nim游戏

    根据 ( exttt{SG}) 定理,这是个最大权值无子集异或和为 (0) 子集模板。

    其他题自己找吧,这些就是最经典巧妙的了。


    祝大家学习愉快!

  • 相关阅读:
    2.vi 和 vim 编辑器
    1.Linux文件及目录结构
    关于聚集表的学习
    一个完整的表维护程序
    转换函数CONVERSION_EXIT_TSTRN_OUTPUT
    ABAP常用字符串处理
    函数中的异常参数设计
    数据元素文本增强(修改标准数据元素描述)
    锁对象的维护
    在物理表中分配搜索帮助
  • 原文地址:https://www.cnblogs.com/Wendigo/p/12828397.html
Copyright © 2011-2022 走看看