• 异或空间与高斯消元


    1.异或空间相关概念

    1.1 异或空间:依据线性空间的概念,我们可以进一步推广,不限于向量、向量加法和标量乘法。“异或空间”也是一个很常见的形式。异或空间是一个关于异或运算封闭的非负整数集合。可以在异或空间中用类似方法定义“表出” “线性无关” “基底” 等概念。(注:线性空间又称向量空间,是线性代数中的重要概念,用来处理代数运算以及其它更抽象的问题。)

    1.2 表出:若整数b能由整数 a1,a2,...,ak 经异或运算得出,则成b能被 a1,a2,...,ak 表出

    1.3 线性相关与线性无关:任意选出异或空间中的若干个整数,如果其中存在一个整数能被其它整数表出,则称这些整数线性相关,否则线性无关

    2.相关考点

    2.1 求基底:给定n个0~2^m-1之间的整数,a1,a2,...,an ,如何求出着n个整数表出的异或空间的基?

    答:我们可以把它们看作m位二进制数,写成一个n行m列的01矩阵,矩阵第i行从左到右依次是ai的第m-1,m-2,...,1,0位(二进制数的最低位称为0位)。把矩阵作为系数矩阵,用高斯消元求解异或方程组的方法,将其转化为简化阶梯型矩阵。简化阶梯型矩阵每一行也是一个整数,所有非零整数一起构成异或空间的基底

    3.例题

    原题链接:XOR  HUOJ3949

    解析:

    用高斯消元求出异或空间的基底。从基底中选取若干个整数(假设t维),显然有 2^t 种方法,因此t维异或空间共有2^t个整数,每个数各不相同,并与每个取法一一对应。

    而高斯消元过程中,共t个主元,而每个主元所对应的列的其它元素都为0,因此每个主元都位于该列最高位,设bi为消元后第 i 个基底,故b1 > b2 > ... > bt,同样的,设 ci 为第i个数主元所在的位置(最低位为0),c1 > c2 > ... > ct。如此一来我们只需将k进行二进制分解,就可以得到第k大的数了。

    这里还需讨论一个情况,那就是异或空间是否含有0。造成这个原因的因为异或空间允许a^a,而本题不允许,也就是说本题不一定含0,而异或空间一定包含整数0。所以我们只需检查简化阶梯型矩阵是否存在“零行”,就可以判断是否可以通过不同的数异或运算得到0。如果可以,本题就该将k从k-1开始分解(按我们的写法0是第0大,而依据题意是第1大),否则从k开始分解(相当于忽略异或空间的0)。

    代码示例:P161——《算法竞赛进阶指南》李煜东

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    using namespace std;
    unsigned long long a[10010];
    int n, m, t, T;
    int main() {
    	cin >> T;
    	for (int C = 1; C <= T; C++) {
    		cin >> n;
    		for (int i = 1; i <= n; i++) scanf("%I64u", &a[i]);
    		bool zero = 0;
    		t = n;
    		for (int i = 1; i <= n; i++) {
    			for (int j = i + 1; j <= n; j++)
    				if (a[j] > a[i]) swap(a[i], a[j]);
    			if (a[i] == 0) {
    				zero = 1, t = i - 1;
    				break;
    			}
    			for (int k = 63; k >= 0; k--)
    				if (a[i] >> k & 1) {
    					for (int j = 1; j <= n; j++)
    						if (i != j && (a[j] >> k & 1)) a[j] ^= a[i];
    					break;
    				}
    		}
    		cin >> m;
    		printf("Case #%d:
    ", C);
    		while (m--) {
    			unsigned long long k, ans = 0;
    			scanf("%I64u", &k);
    			if (zero) k--;
    			if (k >= 1llu << t) puts("-1");
    			else {
    				for (int i = t - 1; i >= 0; i--)
    					if (k >> i & 1) ans ^= a[t - i];
    				printf("%I64u
    ", ans);
    			}
    		}
    	}
    }
  • 相关阅读:
    Css Hack
    flex 兼容 ie9
    js 阻止父级元素的事件向子级元素传递
    php正则表达式的匹配与替换
    php的匿名类的使用
    解决php的单继承问题,实现php的多继承,trait的使用
    php的抽象类和接口的总结和区别
    eclipse的maven项目Java Resources有红叉问题
    IntelliJ全家桶IDEA Webstorm 2020 永久破解方法(说是可以任何版本)
    电脑能ping 通 ip,但是不能ping通 域名
  • 原文地址:https://www.cnblogs.com/long98/p/10352162.html
Copyright © 2020-2023  润新知