线性基及例题 c++

*首先先介绍异或

1^1=0

1^0=1

0^1=1

0^0=0

对于数组a[1],a[2],a[3],.......a[n],异或和

xor_sum=a[1]^a[2]^a[3]^.....^a[n];

再介绍线性基的一些基本性质:

1.可以通过异或 线性基 中的一些数得到原序列里面的任意一个数的异或;

2.原序列的任意子集异或和都能通过线性基里面的一些数异或得到;

3.线性基中的任意几个数的异或和不为0;

4.线性基里面的所有数异或得到原序列的子序列的最大异或和;

5.线性基里面的数的个数唯一,并且在满足1的 情况下,线性基里数的个数是最少的。

线性基的构造:

vector<ull> B;
void insert(ull x)
{
    for(auto b:B)
        x=min(x,b^x);
    for(auto &b:B)
        b=min(b,b^x);
    if(x)
        B.push_back(x);
}

题型:

1.最大异或和:(LibreOJ #113)

给定由n个数组成的一个可重集S,求一个集合T\subseteq S,使T_1 xor T_2 xor ...xor T_{T.size}最大

样例:

1 \leqslant n \leqslant50,0 \leqslant S_i \leqslant 2^{50}

input:

3

5 2 8

output:

15

思路:参考性质4

ac代码:

#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
using namespace std;
typedef unsigned long long ull;
ll n,m,k;
vector<ull> B;
void insert(ull x)
{
    for(auto b:B)
        x=min(x,b^x);
    for(auto &b:B)
        b=min(b,b^x);
    if(x)
        B.push_back(x);
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>n;
    vector<ull> a(n);
    for(auto &x:a)
        cin>>x;
    for(auto x:a)
        insert(x);
    ull ans=0;
    for(auto x:B)
        ans^=x;
    cout<<ans<<endl;
    return 0;
}

2.k大异或和(LibreOJ #114)

题目描述

这是一道模板题。

给由 n 个数组成的一个可重集S ,每次给定一个数 k,求一个集合 T\subseteq S,使得集合 T  在 S  的所有非空子集的不同的异或和中,其异或和  T_1 xor T_2 xor ...xor T_{T.size}是第 k 小的。

 1\leqslant n,m\leqslant10^5,0\leqslant S_i\leqslant2^{50}

输入格式

第一行一个数 n
第二行  n 个数,表示集合 S
第三行一个数 m ,表示询问次数。
第四行  m 个数,表示每一次询问的 k

输出格式

输出  m 行,对应每一次询问的答案,第 k 小的异或和。如果集合 S  的所有非空子集中,不同的异或和数量不足 k ,输出 -1

样例

输入

3
1 2 3
5
1 2 3 4 5

输出

0
1
2
3
-1

思路,先将获得的线性基排序,再根据线性基的性质,将线性基从小到大看作是二进制从小到答案的每一位,设线性基内有m个元素,若m<n,则最多有2^m种情况(线性基内异或得到的数与线性基外的数异或可以为0),若m=n,则最多有2^{m}-1种情况(由性质3可知不可能通过异或得到0)

代码实现:

#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
using namespace std;
typedef unsigned long long ull;
ll n,m,k;
vector<ull> B;
void insert(ull x)
{
    for(auto b:B)
        x=min(x,b^x);
    for(auto &b:B)
        b=min(b,b^x);
    if(x)
        B.push_back(x);
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>n;
    vector<ull> a(n);
    for(auto &x:a)
        cin>>x;
    sort(a.begin(),a.end());
    for(auto x:a)
        insert(x);
    int bs=B.size();
    ll sum=pow(2,bs);
    sort(B.begin(),B.end());
    cin>>m;
    for(int v=0;v<m;v++)
    {
        ll x;
        cin>>x;
        if(x>sum||x<=0)
            cout<<-1<<endl;
        else
        {
            ll ans=0;
            int i=0;
            if(bs!=n)
                x--;
            while(x)
            {
                if(x%2==1)
                    ans^=B[i];
                x/=2;
                i++;
            }
            cout<<ans<<endl;
        }
    }
    return 0;
}

洛谷 P4570 [BJWC2011]元素

题意:有序列a[1],a[2],.....a[n],每个数对应相应能量,求在子序列异或和最大的同时子序列中对应的能量和也最大

输入输出样例

输入 #1

3 
1 10 
2 20 
3 30

输出 #1

50

对于全部的数据:1\leqslant N\leqslant1000,1\leqslant Number_i\leqslant10^{18},1\leqslant Magic_i\leqslant10^{4}

思路:(贪心+线性基)先将按能量从大到小排序,再构造线性基,若数字符合条件进入线性基,则ans+=对应能量

具体代码如下

#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
#define f first
#define s second
using namespace std;
typedef unsigned long long ull;
ll n,m,k;
vector<ull> B;
int insert(ull x)
{
    for(auto b:B)
        x=min(x,b^x);
    for(auto &b:B)
        b=min(b,b^x);
    if(x)
    {
        B.push_back(x);
        return 1;
    }
    else
        return 0;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>n;
    vector<pair<int,ull> >a(n);
    for(auto &x:a)
    {
        cin>>x.s>>x.f;
        x.f=-x.f;
    }
    sort(a.begin(),a.end());
    int ans=0;
    for(auto x:a)
    {
        if(insert(x.s)==1)
            ans-=x.f;
    }
    cout<<ans<<endl;
    return 0;
}

### 回答1: "数据结构经典例题名家代码"是一本经典的数据结构教材,其中包含了许多著名数据结构例题和相关的代码实现。 书中介绍了各种常见的数据结构,如线性结构(数组、链表、栈、队列)、树结构(二叉树、堆、哈夫曼树)、图结构(邻接矩阵、邻接表)等。每个数据结构都有详细的介绍和示例代码,可以帮助读者理解和掌握这些数据结构的本原理和操作。 除了介绍数据结构的本知识之外,书中还包含了许多算法和问题的实际应用。比如,如何使用数据结构解决迷宫问题、查找算法、排序算法等。这些例题和代码展示了数据结构在实际问题中的应用和灵活性,有助于读者培养解决问题的思维方式和能力。 作者通过清晰的讲解和简洁的代码示例,使得读者可以更好地理解和掌握数据结构的本原理和使用方法。书中还附带了一些习题和答案,供读者巩固知识和提升编程能力。 综上所述,"数据结构经典例题名家代码"是一本非常适合学习和了解数据结构的经典教材,它通过丰富的例题和相关代码,帮助读者深入理解和掌握数据结构的概念和应用。无论是初学者还是有一定础的人员,都可以从中受益。 ### 回答2: 经典例题名家代码之一是二叉树的遍历问题。二叉树是一种重要的数据结构,其遍历方式有三种:前序遍历、中序遍历和后序遍历。 前序遍历就是按照“根左右”的顺序访问二叉树的节点。中序遍历按照“左根右”的顺序进行访问,而后序遍历则是按照“左右根”的顺序进行访问。 以前序遍历为例,我们可以使用递归方法来实现。首先遍历根节点,然后递归地遍历左子树,最后递归地遍历右子树。这种递归思想可以通过以下代码实现: ```python class Node: def __init__(self, data): self.data = data self.left = None self.right = None def preorder_traversal(root): if root: print(root.data) preorder_traversal(root.left) preorder_traversal(root.right) # 示例二叉树 # 1 # / \ # 2 3 # / \ \ # 4 5 6 root = Node(1) root.left = Node(2) root.right = Node(3) root.left.left = Node(4) root.left.right = Node(5) root.right.right = Node(6) preorder_traversal(root) # 输出: 1 2 4 5 3 6 ``` 以上代码通过定义一个`Node`类来构造二叉树,并使用递归函数`preorder_traversal()`来进行前序遍历。输出结果为`1 2 4 5 3 6`,表示了二叉树的先序遍历结果。 通过这个经典的例题和代码,我们可以理解并掌握二叉树的遍历方式,深入理解数据结构的本原理和常见操作。这些都是学习和理解数据结构的重要一步。 ### 回答3: 经典例题名家代码中,常见的一个例子是快速排序算法。快速排序算法是一种高效的排序算法,其核心思想是通过将待排序的序列划分为较小和较大的两个子序列,然后递归地对这两个子序列进行排序,最终实现整个序列的有序。 快速排序算法的名家代码主要体现在该算法的划分过程和递归思想上。其中,划分过程的关键是选择一个准元素,并通过交换元素的位置,将小于准元素的元素移到准元素的左边,将大于准元素的元素移到准元素的右边。而递归思想则是对划分后的子序列进行递归调用,直到子序列只有一个元素或为空。 以下是一种经典的快速排序算法的代码示例: ``` void quickSort(int[] arr, int left, int right) { if (left < right) { int pivotIndex = partition(arr, left, right); // 获取准元素的位置 quickSort(arr, left, pivotIndex - 1); // 对准元素左边的子序列进行排序 quickSort(arr, pivotIndex + 1, right); // 对准元素右边的子序列进行排序 } } int partition(int[] arr, int left, int right) { int pivot = arr[left]; // 选择第一个元素作为准元素 int i = left, j = right; while (i < j) { while (i < j && arr[j] >= pivot) { j--; } if (i < j) { arr[i++] = arr[j]; } while (i < j && arr[i] <= pivot) { i++; } if (i < j) { arr[j--] = arr[i]; } } arr[i] = pivot; return i; } ``` 以上是一个典型的快速排序算法的代码实现,通过划分和递归的方式,能够高效地对一个序列进行排序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值