首页 > 其他分享 >线性基基础

线性基基础

时间:2023-10-07 09:56:05浏览次数:34  
标签:return int ll 基础 dfs 异或 线性

launched on 2023.8.30 11:20

参考资料:

Hypoc_:线性基详解

OIwiki:线性基

什么是线性基

这里的线性基指的是 OI 中常用的异或线性基。

个人认为有点类似于向量中的基底,异或线性基就是一组数的集合,每个序列至少有一个线性基,取线性基中的一些数异或起来可以得到原序列中的任意一个数。

线性基的三大性质

异或线性基有一些性质:

  • 原序列里的任意一个数都可以由线性基里的一些数异或得到。
  • 线性基里面的任意一些数异或起来都不能得到 \(0\)。
  • 线性基里面的数个数唯一,且保证性质一的前提下,数的个数最少。

那么想必你已经会了线性基,我们直接开始看例题并讲解吧!

例题

P3812:线性基模板

我们先找到这个序列的线性基,然后从高到位找大的位,找大的位的时候可能会改变小的位,不过问题不大,因为 \((10000)_2>(01111)_2\),所以我们可以保证这样构造的线性基是最优的。

具体的:

建线性基

用 \(a_i\) 表示二进制下最高位为第 \(i\) 位的线性基元素,我们因为这里求的是最大值,所以不难想到从高位到低位建线性基。

结合代码理解:

void add(ll x){
    for(int i=50;~i;--i)//从高位到低位枚举
        if((x>>i)&1)//如果这一位是 1 才可能会产生变化或者贡献
            if(!a[i])return a[i]=x,void();//如果这一位没有,刚好加入
            //然后直接退出,线性基内的元素不能互相更新
            else x^=a[i];//否则用 a[i] 更新 x,保证其最高位小于等于 i
}

查询最大值

也是从高位到低位找,如果这一位没有就用线性基更新答案,之后的更新不会影响前面的位,非常巧妙,因为我们在建立的时候保证了 \(a_i\) 的最高位为 \(i\) 自然不会对大于 \(i\) 的部分造成影响。

ll query(){
    ll res=0;//一开始的数
    for(int i=50;~i;--i)
        if(!((res>>i)&1))res^=a[i];//如果这一位为0就用a[i]更新答案,a[i]为0反正不会对答案造成影响,也不需要特判
    return res;
}

这样做,我们尽可能保证最高位都是 1 了,所以可以保证最大。

P3857 彩灯

题意即给你一些二进制数,问通过彼此异或最多能表示成多少种数。

因为这并没有让你求最值之类的,所以随便从大,从小建线性基都是可以的,因为我们线性基内存的是 \(a_i\) 表示最高位(或者最低位)为 \(i\) 的数,我们可以控制这些位选或者不选,所以最终答案其实就是 \(2^\text{建出来线性基内元素个数}\)。

int cnt;
void add(ll x){
    for(int i=50;~i;--i)
        if((x>>i)&1)
            if(!a[i])return a[i]=x,cnt++,void();
            else x^=a[i];
    return;
}

P4301:新 \(Nim\) 游戏

注意到不管怎样先手是一定输不了的,所以不可能输出 -1(我不管你几堆都变成一堆就不可能输)。

那么我们考虑 \(Nim\) 游戏的必败态:异或和为 0。也就是我们拿了之后,不能让对手有可以拿走一些堆使得剩下的部分异或和为 0 的情况。

也就是先手剩下的堆彼此之间无论怎么异或都不能为 0?

在床上辗转反侧,突然恍然大悟:

线性基第二条性质:
- 线性基里面的任意一些数异或起来都不能得到 $0$。

那就建一个线性基,然后我们留下线性基里面的元素即可。因为对于任意一个非空序列一定有线性基,所以不用担心有必须全部取完的情况。

但是怎样最大呢?很容易想到一个想法就是从大到小加入线性基,看看能不能。这样为什么最优?我们不难发现,对于一个序列,线性基的元素个数是唯一的,但是内容不唯一,那假设我们不往里面放最大的,那就空出来了一个位给小的,此时小的放进去了肯定不是最优的,所以我们从大到小看能不能放即可。判能不能放很简单,就看能不能插进线性基里面即可。

int n,a[101],w[33];
ll ans;
bool add(int x){
    for(int i=30;~i;--i)
        if((x>>i)&1)
            if(!w[i])return (w[i]=x)||1;//如果放的进去就可以不要
            else x^=w[i];
    return 0;//如果最后可以被表示,说明假设放进去一定可能异或为 0,必须拿走
}
int main(){
    n=read();
    for(int i=1;i<=n;i++)
        ans+=(a[i]=read());//先全部拿走
    sort(a+1,a+1+n);
    for(int i=n;i;--i)//从大到小一个一个加入线性基
        if(add(a[i]))ans-=a[i];
    cout<<ans;
}

P4570:元素

这题和上一题思路基本一致,不过这次是在线性基内的我们才能加入答案。

typedef long long ll;
typedef pair<ll,ll> PII;
int n;
ll w[65],ans;
PII a[1002];
bool add(ll x){
    for(int i=62;~i;--i)
        if(x>>i&1)
            if(!w[i])return (w[i]=x)||1;
            else x^=w[i];
    return 0;
}
int main(){
    n=read();
    for(int i=1;i<=n;i++)
        a[i].second=read(),a[i].first=read();
    sort(a+1,a+1+n);
    for(int i=n;i;--i)
        if(add(a[i].second))
            ans+=a[i].first;
    printf("%d",ans);
}

进阶:P4151 最大XOR和路径

无向联通图的 dfs 树

取任意点为起点,跑一遍 dfs(不能重复经过同一点),走出来的就是一棵 dfs 树。

此时树边已经被分成了两种边:树边和非树边。

有向图的 dfs 树的非树边有三种:横叉边,返祖边,前向边(指向后代)。

因为 dfs 的性质,所以无向图的 dfs 树没有横叉边(假如有,那么先遍历到的会通过这条边把它变成自己的子树,此时又变成了返祖边)。

还有一个性质,每条返祖边都对应了一个环,这个图的所有环都可以通过这些环异或出来。

解法

我们发现,我们先随便找到一条从 \(1-N\) 的路径。因为是联通的,所以我们可以随便从一个分支走到一个环,再从那个环走回来,这样路径上的值不会对我们造成贡献,因为走了两遍,而所有的环都能对我们造成贡献,所以我们把所有环都加入线性基中即可。

不需要找全部的环,因为用返祖边对应的环可以将所有的环都异或出来,符合线性基性质,所以我们只需要把所有这样的环都加入线性基即可。

typedef long long ll;
typedef pair<int,ll> PII;
int n,m;
ll w[65],a[50004];
vector<PII>F[50004];
bool vis[50004];
void add(ll x){//线性基模板
    for(int i=62;~i;--i)
        if(x>>i&1)
            if(!w[i])return w[i]=x,void();
            else x^=w[i];
    return;
}
ll query(ll x){//尽可能扩大
    for(int i=62;~i;--i)
        if(!(x>>i&1))x=x^w[i];
    return x;
}
void dfs(int x,int fa,ll res){
    vis[x]=1;a[x]=res;
    for(PII PI:F[x]){
        int y=PI.first;ll w=PI.second;
        if(y==fa)continue;
        if(!vis[y])dfs(y,x,res^w);//没有访问就去访问
        else add(res^w^a[y]);//否则就是返祖边,把环加入线性基
    }
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=m;i++){
        int u=read(),v=read();
        ll w=read();
        F[u].push_back({v,w});
        F[v].push_back({u,w});
    }
    dfs(1,0,0);
    cout<<query(a[n]);
    return 0;
}

后记

基础部分就这么多了,难的我也不会

finished on 2023.8.30 15:05

标签:return,int,ll,基础,dfs,异或,线性
From: https://www.cnblogs.com/NBest/p/17745587.html

相关文章

  • AutoSAR基础_COM
    模块详解:COM: 从应用层传下来数据首先就进入这里,应用层无需关心收发的数据是通过什么总线传输的,应用只需要将它传输给COM即可。这些收发的数据是由用户的DBC文件或者ARXML文件已经定义好了的(这些文件一般OEM整车厂在整车设计的时候就做出来了,里面有总线的网络拓扑图,每个传输的数......
  • 一些转移细节还不太清楚的线性dp
    D.RoundSubset老早写过了,但是边界考虑不太清楚https://codeforces.com/problemset/problem/837/D#include<bits/stdc++.h>#definelllonglongusingnamespacestd;constintN=205,M=30*200;intn,k,ans,t2[N],t5[N],f[2][N][M];//f[i][j]:选了i个,5......
  • 2023-2024-1 20231409佟伟铭 《计算机基础与程序设计》第一周学习总结
    作业信息这个作业属于哪个课程<班级的链接>(2023-2024-1-计算机基础与程序设计)这个作业要求在哪里<作业要求的链接>(2023-2024-1计算机基础与程序设计第一周作业这个作业的目标<计算机基础与程序设计中的问题>作业正文https://www.cnblogs.com/twma......
  • 线性代数01
    配图是:ArianaGrande,2023年世界最美女人第三名。这是麻省理工18.06课程,线性代数(LinearAlgebra),讲课的是W.GilbertStrang。课本用的书是《IntroductiontoLinearAlgebra》。coursewebpage上有大量的exercises、matlab代码、课程的syllabus。课程的网页是web.mit.edu/......
  • 2023-2024-1学号20231407陈原《计算机基础与程序设计》第一周学习总结
    这个作业属于哪个课程2023-2024-1-计算机基础与程序设计这个作业要求是什么2023-2024-1计算机基础与程序设计第一周作业这个作业的目的是什么简单浏览《计算机概论》,提出疑问,并尝试解决问题    作业正文 https://www.cnblogs.com/CCCY12345/p/17744827.ht......
  • C基础-初始指针
    何为指针?可以通过指针找到以其为地址的内存单元。指针就是变量,只不过存放在指针的值被当做地址处理指针和指针类型根据下图我们可知不同指针类型的存储大小是一样的,并根据计算机位数决定的,64位一般是8个字节intmain(){ printf("%d\n",sizeof(char*)); printf("%d\n",sizeof(s......
  • 2023-2024-1 20231428《计算机基础与程序设计》第一周学习总结
           这个作业属于哪个课程2023-2024-1-计算机基础与程序设计            作业要求https://www.cnblogs.com/rocedu/p/9577842.html#WEEK01          这个作业的目标快速阅读教材,初步了解所学内容 ......
  • 十四天学会C++之第四天(面向对象编程基础)
    类和对象是什么?在C++中,类是一种用户定义的数据类型,它可以包含数据成员(也就是属性)和成员函数(也就是方法)。类是一种模板或蓝图,用于创建具体的对象。对象是类的实例,它是根据类的定义创建的,可以用来表示现实世界中的各种事物。对象具有类定义的属性和行为。面向对象编程思想面向对象编......
  • 2023-2024-1 学号20231315《计算机基础与程序设计》第二周学习总结
    学期:2023-2024-1学号:20231315《计算机基础与程序设计》第二周学习总结作业信息这个作业属于哪个课程2023-2024-1《计算机基础与程序设计》这个作业要求在哪里2023-2024-1《计算机基础与程序设计》这个作业的目标学习计算机科学概论第1章和《C语言程序设计》第1......
  • 网络编程基础
    网络编程InetAddress类表示IP对象的一个类publicstaticvoidmain(String[]args)throwsUnknownHostException{//获取本机的ip对象//InetAddressip=InetAddress.getLocalHost();//获取域名//System.out.println(ip.getHostName());//获取真......