首页 > 其他分享 >线性基基础入门|求线性基|最大异或和|第k大异或和|判断一个数能否用线性基表示

线性基基础入门|求线性基|最大异或和|第k大异或和|判断一个数能否用线性基表示

时间:2022-10-24 23:01:21浏览次数:67  
标签:入门 -- ll 1ll 异或 ans 线性

前置知识:

(今天刚知道的

#acm:异或满足结合律,交换律,x ^ x = 0;

#线性代数关于最大无关组的基本知识

-------我是正文------

给定一个数组a1,a2,a3,a4,a5..

数组a的线性基b为b1,b2,b3

线性基就是线性代数里面的最大无关组,所以满足最大无关组的性质

性质一:比如线性基可以表示一组数里的所有元素,也就是说,可以用线性基的组合去凑出其他元素

bi必定可以写成的形式,其中Xi是系数,且表达方式是唯一的。

 

性质二:再比如线性基里面挑选任意元素,必定不能组合出0

这是因为若a1 ^ a2 ^ a3 ^ .. an=0

根据XOR的性质有:当且仅当x ^ x =0,那么x就可以写成: a1 ^ a2 ... ^ ai = ai+1 ^ ai+2 ... ^ an = x
那么x就有两种表示方式,这和表达方式是唯一的矛盾。

 

 性质三:一个数列可能有多个线性基,但是线性基里数的数量一定唯一,而且是满足性质一的基础上最少的

这跟一组数可能有若干个最大无关组,但是数量肯定是确定的,并且是最少的是一样的,可以用线性代数的角度理解。

 

                    -----摘自某谷,从XOR的角度理解

 

除了这种普通的性质以外,线性基还满足:

每个数的最高位在的位置互不相同,这就是说:

 1 0 0 0 1 0

    1 1 0 1 0

       1 0 0 1

是合理的(先不管满不满足其他,但是:

1 0 0 0 1 0

   1 0 1 0 1

   1 1 0 1 0

就不可以,因为有两个元素的最高位相同了。

先介绍数x的插入过程:

// 将一个数插入线性基 
void ins(ll x){
    for(ll i=62;i>=0;i--){
        if(x&(1ll<<i)){
            if(!p[i]) {p[i]=x,cnt++;break;}
            else x^=p[i];
        }
    }
}

考虑:如果x能够被线性表出,那么x会表达成a1 ^ a2 ^ a3 ^ a4 = 0

那我们就去模拟这个线性表出的过程,如果不能被线性表出,也就是说在某一位有p[i]==0,那我们就加入,and 给它break掉了啦

观察x的插入过程,如果最高位相同,x会被^掉,所以当前位不可能有两个1。

(这里的理解自己觉得会有点问题,有bug请指正

 

-----讲解一下代码~

 check一个数能否被线性表出:

ll aks(ll x){
    for(ll i=62;i>=0;i--)
        if(x&(1ll<<i)) x^=p[i];
    return x==0;
}

(细心的读者可以发现和上面,ins(x)的代码是很像的~

3.

求异或和最大值,原理是基于贪心,因为

 

 

 所以从高到低位枚举,当前能选的话尽量选

// 按位贪心,高位的权重一定是大于(小于它的所有位的和 )
ll askmx(){
    ll ans=0;
    for(ll i=62;i>=0;i--)
        if((ans^p[i])>ans) ans^=p[i];
    return ans;
}

查询第k小:

首先rebuild一个数组,把上面处理出来的线性基再进行一个操作,使得尽量是这种形式:

1 0 0 0 0

   1 0 0 0

         1 0

如何变成这种形式?

对于p[i],如果 : p[i]&(1<<j ) ,就是说如果我们处理出的线性基p[i]在第j位(j-1)上有1,那么就可以把

p[i] -> p[i]^p[j],把当前位上的1消掉,你可能奇怪为什么这么处理完还满足上面所述的种种性质?

可以这么yy:其实对于p[i]来说,我们看重的是它的第i位(所以这也是为什么我们枚举j从i-1开始),那么其他位:

假设p[i]在经过一系列操作,异或上x1,x2,x3...xn后变成了p[i]',我们使用p[i]‘来代替p[i]一定是对的,还更方便

这是因为你还可以再把p[i]'异或上x1,x2,x3...xn给它变回去

处理出这样的d数组后,如何查询第k小?

首先讨论边界(肯定不能大于1<<2的(线性基个数))

然后:

ll ans=0;
    for(ll i=62;i>=0;i--)
        if(k&(1ll<<i)) ans^=d[i];
    return ans;

哇,为什么是对的???为什么???虽然直觉看起来很真(划掉)

 

这段证明说的是两数之间的比较其实比的是从高到低第一个不同的位的大小(有点像字典序)

所以当异或上第i位(有值的第i位,也就是不为0)后,前面i-1个如何组合,也无法比当前的大

那前面的组合就是2的i次方,第j位同理...

这样枚举一遍后(正序逆序都可以,因为二进制拆分是唯一的),我们得到的数前面有:

2的a0次方+2的a1次方+2的a2次方....(就是k的二进制拆分啦)~

void rebuild(){
    cnt=0;top=0;
    for(ll i=62;i>=0;i--)
     for(ll j=i-1;j>=0;j--)
      if(p[i]&(1ll<<j)) p[i]^=p[j];
    for(int i=0;i<=62;i++) if(p[i]) d[cnt++]=p[i]; 
}
ll kth(ll k){
    if(k>=(1ll<<cnt)) return -1;
    ll ans=0;
    for(ll i=62;i>=0;i--)
        if(k&(1ll<<i)) ans^=d[i];
    return ans;
}

完整模板:

瓶颈是n²,所以数据可以开到5000

(也许高斯消元可以做得更好,但是还没学x

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll top,p[100],d[100],cnt;
// 将一个数插入线性基 
void ins(ll x){
    for(ll i=62;i>=0;i--){
        if(x&(1ll<<i)){
            if(!p[i]) {p[i]=x,cnt++;break;}
            else x^=p[i];
        }
    }
}
//查询一个元素是否可以被异或出来
ll aks(ll x){
    for(ll i=62;i>=0;i--)
        if(x&(1ll<<i)) x^=p[i];
    return x==0;
}
// 按位贪心,高位的权重一定是大于(小于它的所有位的和 )
ll askmx(){
    ll ans=0;
    for(ll i=62;i>=0;i--)
        if((ans^p[i])>ans) ans^=p[i];
    return ans;
}
//查询异或第k小
void rebuild(){
    cnt=0;top=0;
    for(ll i=62;i>=0;i--)
     for(ll j=i-1;j>=0;j--)
      if(p[i]&(1ll<<j)) p[i]^=p[j];
    for(int i=0;i<=62;i++) if(p[i]) d[cnt++]=p[i]; 
}
ll kth(ll k){
    if(k>=(1ll<<cnt)) return -1;
    ll ans=0;
    for(ll i=62;i>=0;i--)
        if(k&(1ll<<i)) ans^=d[i];
    return ans;
}
int n;
ll a[100];
int main(){
        cin>>n;
        for(int i=1;i<=n;i++) {cin>>a[i];ins(a[i]);}
    
        cout<<askmx()<<endl;
}

 

标签:入门,--,ll,1ll,异或,ans,线性
From: https://www.cnblogs.com/liyishui2003/p/16823176.html

相关文章

  • Hadoop集群简单入门
    Hadoop集群搭建自己配置Hadoop的话太过复杂了,因为自己着急学习,就使用了黑马的快照。如果小伙伴们也想的话可以直接看黑马的课程,快照的话关注黑马程序员公众号,输入Hadoop就......
  • C++算法之旅、01 入门篇
    使用胡凡主编的《算法笔记》教材。题目均为第三章题目。TEST//ProblemAddress#define_CRT_SECURE_NO_WARNINGS#include<cstdio>intmain(){return0;}PAT......
  • C语言入门-1-编译器的基本使用(Dev c++和visual studio)
    一、Devc++打开软件点击文件,新建,项目 选择Console点击helloworld,勾选c项目,名称自行输入点击确定后出现文件位置,自行安放在文件夹里保存后即可进行编译运......
  • 02Jmeter之Jmeter入门
    一、JMETER目录结构 bin:该目录存放的是Jmeter的主jar、相关的启动脚本、配置文件和日志文件等a) examples目录中有CSV样例b) jmeter.batwindows的启动文件c)......
  • 看代码的技巧 要将线性的代码转换成结构性的代码
    函数中代码的结构,三个循环结构嵌套一个分支结构就是我们在看分支结构的时候,习惯了将分支结构看成一个线性的结构,也就是顺序结构,虽然执行顺序上类似线性结构,但是我们......
  • [NOI Online #1 入门组] 跑步 题解
    [NOIOnline#1入门组]跑步题解一个经典问题:计数将正整数\(n\)拆分为若干个正整数的方案数,这里拆成的正整数是无序的,对\(P\)取模。容易得到\(O(n^2)\)解法设\(f_{i,j......
  • Python获取手机4K壁纸,一个入门练手的案例
    前言一.数据来源分析明确需求,我们采集网上什么数据内容,在什么地方分析我们想要高清原图在什么地方有浏览器自带工具:开发者工具F12鼠标右键点击......
  • 手把手带你入门 API 开发
    引言在本文中,您将学习如何使用​​Flask​​​、​​SQLite3​​(轻易数据库)和JSON创建用于数据通信的RESTAPI。本文使用4个最常用的HTTP动词:GET、POST、PUT和DE......
  • Selenium4Web自动化11-分布式测试Grid入门到实战
    一、Grid介绍要在多台计算机上并行运行测试吗?那么,Grid正是为你准备的.SeleniumGrid允许通过路由命令在远程机器上执行WebDriver脚本,这些命令由客户机发送到远程浏览......
  • python渗透测试入门——基础的网络编程工具
    《Python黑帽子——黑客与渗透测试编程之道学习》这本书是我在学习安全的过程中发现的在我看来十分优秀的一本书,业内也拥有很高的评价,所以在这里将自己的学习内容分享出来......