ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

线性基

2019-01-31 16:39:52  阅读:408  来源: 互联网

标签:11 基中 凑出 集合 异或 线性


线性基

定义

线性基

一个由若干数组成的集合\(S\),定义它的线性基为最小的一个集合\(T\)使得\(S\)和\(T\)能够异或出的值域(集合)相同

张成

一个集合\(S\),随意取若干个数异或,能够凑出的数的集合称为集合\(S\)的张成,表示为\(span(S)\)

线性相关

如果一个集合内有某个数满足:去除这个数后的集合可以凑出这个数。那么称集合\(S\)线性相关。否则为线性无关

求法

将每个数看做一个01串,按位操作,从高到低,在没加入线性基的数中找,看有没有当前位为1的,如果有,将其加入线性基中,并用现在加入线性基中的这个数 消去 原本线性基中其他数当前位的1(高斯消元)。如果没有,跳过当前位直接对下一位进行操作

这样消出的线性基满足每一列最多只有一个1,并且从前往后,线性基中每个数的第一个1所在位置依次右移,即前面的数严格大于后面的数。
类似于这样的形式:
\[1001010101\\ 0101010101\\ 0010110101\\ 0000011010\\ .\\ .\\ .\\ \]

证明

考虑这样为什么这样求出的线性基是合法的。(不知道怎么证这样一定是最小的)
由线性基的定义可得,如果\(S\)集合中的每个数,都可以被\(T\)集合表示出,那么这组线性基一定合法,因此我们只需要考虑能否凑出\(S\)集合即可。
对于\(S\)集合中的任意一个数的任意一位,如果这一位无法被凑出,意味着这一位是1,但线性基中却没有这一位是1的数,但如果这样,这个无法被凑出的数就应该在当时被加入线性基中,所以这样的数不存在。

你可能会有这样的疑问:是否可能有一个数因为线性基中某几位被捆绑在一起而无法凑出?
考虑几个位为什么会捆绑在一起?因为一开始加入的某个数在这几位上是1,但后面却没有在这一位上是1的数(消去后)。
一个数如果会因为某几位被捆绑而无法凑出,只可能是实际上是10,但只能凑出11(线性基中只有11,没有1x和01).但这种情况是不可能的,因为当我们将11加入线性基时,由于10的首位是1,所以11会对10进行消数的操作,使得10变为01,这时,第二位是1的数是存在的,所以11不会被捆绑在一起。

性质/用法

性质1

1,假设原来的集合大小为\(|S|\),线性基大小为\(|T|\),对于任意一个数\(x\),如果它可以被线性基中的数表示出来,那么从集合\(S\)中选若干个数\(xor\)出\(x\)的方案数为\(2^{|S| - |T|}\)。
证明:考虑\(|S| - |T|\)实际上就是集合中没有加入线性基中的数的个数,我们在这个集合中任意选一些数的方案数为\(2^{|S| - |T|}\),而每一种取法异或出来的数,都可以由线性基中的某一个确定的方案凑出。将这2个相同的数异或,可以得到\(0\),因此我们有\(2^{|S| - |T|}\)种凑出\(0\)的方案。
因此对于任意一个数,如果我们可以用线性基凑出,我们可以拿它和凑\(0\)的方案进行异或,所以肯定也有\(2^{|S| - |T|}\)种方案,否则肯定就凑不出了。

用法1

线性基可以判断任意一个数是否可以被集合\(S\)内的数凑出。

从高位开始,依次操作,如果当前位为1,那么异或上线性基中当前位为1的数,否则不操作。最后判断结果是否为0,为0即可以凑出(一个数在异或后变成了0,肯定是因为这个数异或上了它自己)

由此我们可以引申出另一个经典用法:用线性基来求一个集合的最大异或和。
从高位开始贪心,每次检查异或上线性基的当前位是否可以使得答案变大,如果可以,就异或,否则跳过。

求最大异或和的代码:

#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 55
#define LL long long

int n, tot;
LL maxn, ans;
LL f[AC];

inline LL read()
{
    LL x = 0;char c = getchar();
    while(c > '9' || c < '0') c = getchar();
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x;
}

void pre()
{
    n = read(), maxn = 1LL << 50;
    for(R i = 1; i <= n; i ++, maxn = 1LL << 50) 
    {
        LL x = read();
        for(R j = 50; ~j; j --, maxn >>= 1)
        {
            if(!(x & maxn)) continue;
            if(!f[j]) {f[j] = x; break;}
            else x ^= f[j];
        }
    }
}

void work()
{
    for(R i = 51; ~i; i --)
        if((ans ^ f[i]) > ans) ans ^= f[i];
    printf("%lld\n", ans);
}

int main()
{
    //freopen("in.in", "r", stdin);
    pre();
    work();
//  fclose(stdin);
    return 0;
}

标签:11,基中,凑出,集合,异或,线性
来源: https://www.cnblogs.com/ww3113306/p/10342527.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有