• P3812 【模板】线性基


    不得不说,线性基是一个神奇的东西

    它维护的东西与“异或”密切相关

    题意:

    给定n个整数(数字可能重复),求在这些数中选取任意个,使得他们的异或和最大。

    当然,也可以最小,甚至,可以求任意异或和第k大!(哇,好niubi)

    做法:开一个数组a[MAXN],MAXN是数字最高位数。

      a[i]表示当前线性基内任意异或出来的数字中,最高位为i的任意一个数字。

    插入x|判断x是否存在

    从高位到低位枚举所有位数,如果x的第i位有值:如果a[i]不存在,则a[i]=x,并退出。

                 如果a[i]存在,令x^=a[i]。如果最后x变成了0,那么说明x在线性基内。

    inline bool insert(int x)
    {
        for(int i=nmr;i>=0;i--)
        {
            if(x&(1LL<<i))
            {
                if(a[i]==0)
                {
                    a[i]=x;
                    break;
                }
                x^=a[i];
            }
        }
        return x>0;
    }

    查询最大值

    从高位到低位扫描线性基。如果异或之后答案变大,就把这一位异或到答案。

    inline int get_max()
    {
        int ans=0;
        for(int i=nmr;i>=0;i--)
        { 
            if((ans^a[i])>ans)
                ans^=a[i];
        }
        return ans;
    }

    查询最小值

    从低位到高位扫描线性基。最低位上的线性基即为答案。

    inline int get_min()
    {
        for(int i=0;i<=nmr;i++)
            if(a[i]>0) return a[i];
    }

    第k小

    首先我们要改造一下线性基。我们把线性基改造成每一位相互独立,意思就是对于第i位,

    线性基上只有第i位可能是1。(其它位是1就不相互独立了(互相异或不对了))具体如何改造,就是从高位向低位扫描,

    对于第i位线性基a[i],对于j<i,如果a[i]的第j位是1,就让a[j]异或上a[i]。

    查询的时候,将k进行二进制拆分,对于的1位,就异或对应的线性基。

    最终得到的答案是第k小值。

    inline void rebuild()
    {
        cnt=0;
        for(int i=nmr;i>=0;i--)
        {
            for(int j=i-1;j>=0;j--)
                if(a[i]&(1LL<<j))
                    a[i]^=a[j];
        }
        for(int i=0;i<=nmr;i++)
            if(a[i])
                p[cnt++]=a[i];
    }
    inline int query(int k)
    {
        int ans=0;
        if(k>=(1LL<<cnt)) return -1;
        for(int i=nmr;i>=0;i--)
        {
            if(k&(1LL<<i))
                ans^=p[i];
        }
        return ans;
    }

    so

    线性基码量小,而且速度快(遇到异或问题可以想到线性基666)

    基于本题:只要查询最大值即可,这里给出全代码

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    #define olinr return
    #define nmr 60
    #define love_nmr 0
    #define int long long
    int a[nmr];
    int cnt;
    int n;
    int x;
    int p[nmr];
    inline bool insert(int x)
    {
        for(int i=nmr;i>=0;i--)
        {
            if(x&(1LL<<i))
            {
                if(a[i]==0)
                {
                    a[i]=x;
                    break;
                }
                x^=a[i];
            }
        }
        return x>0;
    }
    inline int get_max()
    {
        int ans=0;
        for(int i=nmr;i>=0;i--)
        { 
            if((ans^a[i])>ans)
                ans^=a[i];
        }
        return ans;
    }
    inline int get_min()
    {
        for(int i=0;i<=nmr;i++)
            if(a[i]>0) return a[i];
    }
    inline void rebuild()
    {
        cnt=0;
        for(int i=nmr;i>=0;i--)
        {
            for(int j=i-1;j>=0;j--)
                if(a[i]&(1LL<<j))
                    a[i]^=a[j];
        }
        for(int i=0;i<=nmr;i++)
            if(a[i])
                p[cnt++]=a[i];
    }
    inline int query(int k)
    {
        int ans=0;
        if(k>=(1LL<<cnt)) return -1;
        for(int i=nmr;i>=0;i--)
        {
            if(k&(1LL<<i))
                ans^=p[i];
        }
        return ans;
    }
    signed main()
    {
        ios::sync_with_stdio(false);
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>x;
            insert(x);
        }
        cout<<get_max();
        olinr love_nmr;
    }
  • 相关阅读:
    小程序(四):模板
    小程序(三):授权登录
    小程序(二)
    小程序(一)
    从零开始学习微信小程序
    flex 弹性布局
    如何使用docker进行shadsocks环境开发配置
    eclipse 设置注释模板
    idea 2019.1.3最新注册码
    centos7安装rabbitmq简单方式
  • 原文地址:https://www.cnblogs.com/olinr/p/9477787.html
Copyright © 2020-2023  润新知