• 线性基学习笔记


    补坑

    线性基在我的理解来看,就是把原来较大的集合转换成最大的数的二进制位数大小的集合。通过这个操作可以用选择子集异或的形式表示出原集合。

    基础实现

    每次插入一个数就从高位到低位,如果这位是1的话,分两种情况。如果线性基里存在这一位了,那么这个数异或上线性基里的数,不然的话线性基里这一位数就是这个数啦。

    代码实现很简单。

    void build(ll x)
    {
    	for(int i=lg-1;i>=0;i--)
    	{
    		if(x&(1ll<<i))
    		{
    			if(ext[i])	x^=s[i];
    			else{s[i]=x,ext[i]=1;break;}
    		}
    	}
    }

    写丑了嘤嘤嘤

    维护对角矩阵

    把线性基看成一个矩阵,利用类高斯消元法的方法维护。这就是是一个矩阵且每一列至多有1个1,且这些1一定是在上三角中。这个很明显,因为第k位上的1一定只会出现在前k行而一定不会出现在后面,所以满足一个上三角矩阵。

    实现其实很简单啦,就是通过第i行下面的消自己,再用第i行去消上面。

    【听大佬说这玩意没用。。。】

    for(int i=lg-1;i>=0;i--)
    	{
    		if(x&(1ll<<i))
    		{
    			if(ext[i])	x^=s[i];
    			else
    			{
    				s[i]=x,ext[i]=1;
    				for(int j=i-1;j>=0;j--)	if(s[j]&&s[i]&(1<<j))	s[i]^=s[j];
    				for(int j=i+1;j<lg;j++)	if(s[j]&&s[j]&(1<<i))	s[j]^=s[i];
    				break;
    			}
    		}
    	}

    题目

    洛谷模板

    求异或最大值。

    显而易见,肯定要根据原集合建线性基。然后贪心的从高位到低位选择。如果答案异或上当前这个数可以变大的话就异或上。

    这个的正确性是因为对于第k位,只有前k个数可能能影响到这一位。如果现在在第k位且异或上答案变大(0->1),那么接下来的数异或一定不会影响这一位。这个思想其实类似字典序?

    洛谷【P3857】[TJOI2008]彩灯

    题意:有n个彩灯,一些开关,每个开关可以控制某些彩灯。问有几种不同的样式。

    分析一下。每个灯代表1位的话,那么每个开关对应一个数,求异或后有多少种不同的取值。那么直接扔进线性基,看有多少位是可以异或的,那么最后的答案就是2^k k表示线性基中数的个数。

    这个比较好理解,就是这些数可以控制这一位0/1,所以最后的答案就是这k位各取0,1的方案数。

    洛谷P4151 [WC2011]最大XOR和路径

    题意:找一条路径,要求异或和最大。

    我不会做。看的题解。

    大概是这个样子。对于一条边如果往返走,它对答案没有贡献。(异或为0)也就是说我们现在有一条1-n的简单路径,然后如果我们想要异或其他值的话,只有可能异或上环。因为如果不是环的话一定是走了两遍。所以把所有环扔进线性基,然后最后把简单路径作为起始值,求异或最大值就行啦。

    问题来了,如何选择这个简单路径。

    其实选择哪一条都行,因为如果我们当前的路径不是最优的话,另一条路径一定和当前路径构成环。(都是从1-n,所以一定构成环)那么我们放在线性基里的时候异或上这个环的话,我们的简单路径实际上就变成了那个更优的。

    如下图。红色更优,那么我们异或上中间的环,就从红色变成蓝色了。

    代码实现很简单就跑个dfs就ok。

    void dfs(int x)
    {
    	vis[x]=1;
    	for(int i=in[x];i;i=e[i].lt)
    	{
    		int v=e[i].to;
    		if(vis[v])	insert(dis[x]^dis[v]^e[i].v);
    		else	dis[v]=dis[x]^e[i].v,dfs(v);
    	}
    }

    线性基还是比较好理解的一个东西[只要别带着那些概念/捂脸]

    以后再补题吧qwq

    10.11update

    溺死在初赛的hywn冒个泡

    见到一道比较有意思的题qwq

    给定一个集合,求每次删除一个元素的异或最大值。

    首先,线性基不资瓷删除。所以直接做是不可楞滴。

    我们发现每次只删除一个元素,诶嘿嘿,我们直接对于前缀记录线性基,后缀记录线性基,然后暴力合并/xyx

    时间复杂度O(nlg^2n)空间O(nlgn)

    所以这个题其实可以拓展到区间一样做qwq

  • 相关阅读:
    “ODBC驱动程序不支持动态记录集”错误的解决
    Pro *C/C++学习笔记(一)
    探讨全局变量的析构顺序
    指针和数组关系初探
    (转)Visual C++开发工具与调试技巧整理
    对利用Session纪录datagrid模板列中CheckBox的状态的一点改进
    大学老师列传
    重读保尔的意义
    Rich Edit控件的使用
    C++程序员常用工具集
  • 原文地址:https://www.cnblogs.com/hanyuweining/p/10321982.html
Copyright © 2020-2023  润新知