线性基

1、线性基:一组线性无关的向量作为基底,张起一个线性的向量空间。这个基底称为线性基。线性基的基底通过线性运算,可以表示向量空间内的所有向量。

2、线性相关:在向量空间V的一组向量A:如果存在不全为零的数 k1, k2, ···,km , 使

则称向量组A是线性相关的,否则数 k1, k2, ···,km全为0时,称它是线性无关。
简单的说,线性相关就是其中一个向量能够被其他向量表示出来,不能表示出来就是线性无关。

3、设数集T的值域范围为[1,2n−1]。
T的线性基是T的一个子集A={a1,a2,a3,…,an}
A中元素互相xor所形成的异或集合,等价于原数集T的元素互相xor形成的异或集合。

4、性质
1、线性基的异或集合中不存在0,等价于每个元素的异或方案唯一
2、线性基二进制最高位1的位置互不相同,最高位的1唯一,且base[i]就是最高位(第i位)为1的唯一向量,
3、如果线性基是满的,它的异或集合为[1,2n−1]
4、线性基中元素互相异或,异或集合不变。即,任取向量组中两个向量a、b,把其中一个替换成a xor b,这组向量线性组合得到的线性空间相同

1、插入
从高位到低位扫描x二进制中的1,如果扫到第i位,此时的base[i]为0(不存在),把x作为向量,加入线性基并结束。如果存在了,让x异或base[i],把x第i位的1消去。对于新得到的x,继续往低位扫,取高位的1,重复操作。
这样就得到了性质:最高位1的位置互不相同(相同的都被抵消了,不存在才会加上去)

bool Insert(ll x)
{
    for(int i=32;i>=0;--i)
    {
        if(x&(1ll<<i))
        {
            if(!base[i])
            {
                base[i]=x;
                break;
            }
            x^=base[i];
        }
    }
    return x>0;
}

2、合并
将一个线性基暴力插入另一个线性基即可

LinearBase Merge(const LinearBase &a,const LinearBase &b)
{
	LinearBase ret=a;
	for(int i=60;i>=0;--i)
		if(b.base[i])
			ret.Insert(b.base[i]);
	return ret;
}	

3、查询是否存在x
方法一:从高位往低位扫描x,如果x的第i位为1,但不存在向量d[ i ] ,这样便不可能将x异或为0,也就是不存在这样的x。否则x就异或d[i],如果到最后x变为0,则空间中存在这样的x
方法二:把它尝试插入进线性基里面去,假如可以插入,说明不能异或得到,假如插不进去,说明不能异或得到

bool find(ll x)
{
    for(int i=32;i>=0;--i)
    {
        if(x&(1ll<<i))       
        {
            if(!base[i])
                break;
            x^=base[i];
        }  
    }
    return x==0;
}   

4、查询最大
从高位到低位扫描线性基。如果异或后可以使得答案变大,就异或到答案中去

ll QueryMax()
{
	ll ret=0;
	for(int i=60;i>=0;--i)
		if((ret^base[i])>ret)
			ret^=base[i];
	return ret;
}	

5、查询最小
最低位的向量,就是最小值

ll QueryMin()
{
	for(int i=0;i<=60;++i)
		if(base[i])
			return base[i];
	return 0;
}

6、查找第k小的值
首先对线性基进行改造,改造的结果是:一个向量二进制中最高位的1只出现在自己身上,其余向量在该位置都为0。比如,23:10111,15:1111,1:1,在改造完之后,变成了22:10110,15:1110,1:1
改造方法:从大到小枚举每一个线性基d[i],从它的第二高位往低位扫,如果扫到d[i]在第j位是1,那么就异或上d[j](d[j]最高位是1),这样就消去d[i]在第j位上的1。当然d[ j ]这个向量可能不存在。那么原本该位的1不变。当线性基饱和后,能异或出 1-2^n 中的任意一个数 。
所以查询的时候将k二进制拆分,对于1的位,就异或上对应的线性基。 最终得出的答案就是第k小的值。
注意判断0的情况, 也就是原序列有可能异或出0的情况来, 而这个线性基是判断不了的, 所以我们要人为判断, 那怎么判断了, 实际上就是如果插入到线性基中的数不是全体的数, 那么必定有零的这个元素的出现。想想插入的过程就懂了, 如果有零, 那么还需要k – 之后,再进行判断。
如果线性基的大小和原数组一样,0是不能被异或出来的,否则可以。
注意long long,判断无解的时候 要写成1ll,即k>=(1ll<<cnt)

    void Rebuild()
    {
        for(int i=32;i>=0;i--)
            for(int j=i-1;j>=0;j--)
                if(base[i]&(1ll<<j))
                    base[i]^=base[j];
        for(int i=0;i<=32;++i)
            if(base[i])
                p[cnt++]=base[i];
    }

	ll KthQuery(ll k)
	{
		ll ret=0;
		if(k>=(1ll<<cnt))	
			return -1;
		for(int i=60;i>=0;i--)
			if(k&(1ll<<i))
				ret^=p[i];
		return ret;
	}

板子

struct LinearBase
{
    ll base[35],p[35];
    int cnt;
    LinearBase()
    {
        memset(base,0,sizeof(base));
        memset(p,0,sizeof(p));
        cnt=0;
    }
 
    bool Insert(ll x)
    {
        for(int i=32;i>=0;--i)
        {
            if(x&(1ll<<i))
            {
                if(!base[i])
                {
                    base[i]=x;
                    break;
                }
                x^=base[i];
            }
        }
        return x>0;
    }
    	
	LinearBase Merge(const LinearBase &a,const LinearBase &b)
	{
		LinearBase ret=a;
		for(int i=60;i>=0;--i)
			if(b.base[i])
				ret.Insert(b.base[i]);
		return ret;
	}	
    
	ll QueryMax()
	{
		ll ret=0;
		for(int i=60;i>=0;--i)
			if((ret^base[i])>ret)
				ret^=base[i];
		return ret;
	}		
	
	ll QueryMin()
	{
		for(int i=0;i<=60;++i)
			if(base[i])
				return base[i];
		return 0;
	}
     
    void Rebuild()
    {
        for(int i=32;i>=0;i--)
            for(int j=i-1;j>=0;j--)
                if(base[i]&(1ll<<j))
                    base[i]^=base[j];
        for(int i=0;i<=32;++i)
            if(base[i])
                p[cnt++]=base[i];
    }
 
    bool find(ll x)
    {
        for(int i=32;i>=0;--i)
        {
            if(x&(1ll<<i))       
            {
                if(!base[i])
                    break;
                x^=base[i];
            }  
        }
        return x==0;
    }      
};
 
LinearBase Intersection(LinearBase A,LinearBase B)
{
    LinearBase All,C,D;
    for (int i=32;i>=0;i--)
        All.base[i] = A.base[i];
              
    for (int i=32;i>=0;i--)
        if(B.base[i])
        {
            ll v=B.base[i],k=1ll<<i;
            bool can = true;
            for (int j=32;j>=0;j--)
            {
                if (v&(1ll<<j))
                {
                    if (All.base[j])
                    {
                        v^=All.base[j];
                        k^=D.base[j];
                    }
                    else
                    {
                        can = false;
                        All.base[j]=v;
                        D.base[j]=k;
                        break;
                    }
                }
            }
      
            if (can)
            {
                ll v=0;
                for(int j=32;j>=0;j--)
                	if(k&(1ll<<j)) 
						v^=B.base[j];
                C.Insert(v);
            }
        }
    C.Rebuild();
    return C;
}

2019牛客暑期多校训练营(第四场)B xor

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <cstring>
#include <string>
#include <cmath>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define mp make_pair
#define ll long long
#define pb push_back
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define isZero(d)  (abs(d) < 1e-8)
using namespace std;
const int maxn=5e4+5,INF=0x3f3f3f3f;
const int mod=1e9+7;
  
struct LinearBase
{
    ll base[35],p[35];
    int cnt;
    LinearBase()
    {
        memset(base,0,sizeof(base));
        memset(p,0,sizeof(p));
        cnt=0;
    }
  
    bool Insert(ll x)
    {
        for(int i=32;i>=0;--i)
        {
            if(x&(1ll<<i))
            {
                if(!base[i])
                {
                    base[i]=x;
                    break;
                }
                x^=base[i];
            }
        }
        return x>0;
    }

    void Rebuild()
    {
        for(int i=32;i>=0;i--)
            for(int j=i-1;j>=0;j--)
                if(base[i]&(1ll<<j))
                    base[i]^=base[j];
        for(int i=0;i<=32;++i)
            if(base[i])
                p[cnt++]=base[i];
    }
  
    bool find(ll x)
    {
        for(int i=32;i>=0;--i)
        {
            if(x&(1ll<<i))      
            {
                if(!base[i])
                    break;
                x^=base[i];
            } 
        }
        return x==0;
    }     
};
  
LinearBase Intersection(LinearBase A,LinearBase B)
{
    LinearBase All,C,D;
    for (int i=32;i>=0;i--)
        All.base[i] = A.base[i];
               
    for (int i=32;i>=0;i--)
        if(B.base[i])
        {
            ll v=B.base[i],k=1ll<<i;
            bool can = true;
            for (int j=32;j>=0;j--)
            {
                if (v&(1ll<<j))
                {
                    if (All.base[j])
                    {
                        v^=All.base[j];
                        k^=D.base[j];
                    }
                    else
                    {
                        can = false;
                        All.base[j]=v;
                        D.base[j]=k;
                        break;
                    }
                }
            }
       
            if (can)
            {
                ll v=0;
                for(int j=32;j>=0;j--)
                    if(k&(1ll<<j))
                        v^=B.base[j];
                C.Insert(v);
            }
        }
    C.Rebuild();
    return C;
}
  
int n,m;
LinearBase lb[maxn],ST[maxn<<2];
  
void Push_up(int rt)
{
    ST[rt]=Intersection(ST[ls],ST[rs]);
}
  
void Build(int rt,int L,int R)
{
    if(L==R)
    {
        ST[rt]=lb[L];
        return;
    }
    int mid=(L+R)>>1;
    Build(ls,L,mid);
    Build(rs,mid+1,R);
    Push_up(rt);
}
  
bool Query(int rt,int l,int r,int L,int R,ll x)
{
    if(l<=L&&R<=r)
        return ST[rt].find(x);
    int mid=(L+R)>>1;
    bool ret1=true,ret2=true;
    if(l<=mid)
        ret1=Query(ls,l,r,L,mid,x);
    if(r>mid)
        ret2=Query(rs,l,r,mid+1,R,x);
    return ret1&&ret2;
}
  
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;++i)
    {
        int x;
        ll y;
        scanf("%d",&x);
        for(int j=1;j<=x;++j)
        {
            scanf("%lld",&y);
            lb[i].Insert(y);
        }     
    } 
    Build(1,1,n);   
    ll l,r,x;
    while(m--)
    {
        scanf("%lld %lld %lld",&l,&r,&x);
        bool result=Query(1,l,r,1,n,x);
        if(result)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
线性可以用来判断原集合是否封闭。如果一个元素能够被线性向量线性表示,那么它就可以由原集合中的元素经过线性组合得到,即原集合是封闭的。否则,如果有一个元素不能被线性向量线性表示,那么它就无法由原集合中的元素经过线性组合得到,即原集合不是封闭的。 具体地,我们可以通过将待判断的元素与线性向量进行异或操作来判断是否能够线性表示。如果待判断元素与线性向量进行异或操作后得到零向量,则说明待判断元素可以由线性向量线性表示。如果待判断元素与线性向量进行异或操作后得到非零向量,则说明待判断元素无法由线性向量线性表示。 因此,我们可以通过判断待判断元素与线性向量进行异或操作的结果是否为零向量来判断原集合是否封闭。如果待判断元素与线性向量进行异或操作后都得到零向量,则原集合是封闭的;否则,原集合不是封闭的。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [线性模板](https://blog.csdn.net/weixin_43519854/article/details/96977900)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [【矩阵论】线性空间与线性变换(3)(4)](https://blog.csdn.net/kodoshinichi/article/details/108916238)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值