zoukankan      html  css  js  c++  java
  • 线性基模板

    线性基构造方法

    对于每一个数,我们找出他的最高位的 1 在第 i 位, 如果此时 Pi 为零,就将这个数加入线性基,否则异或 Pi 继续找。然后我们就可以在 0 到 k 位上处理好每一位的线性基。这样得到的线性基保证每一位都能有对应的最大值。

    void get_p(LL x)
    {
        for(int i=62;i>=0;i--)
        {
            if((x>>(LL)i))
            {
                if(!p[i])
                {
                    p[i]=x;
                    break;
                }
                x^=p[i];
            }
        }
    }
    

    求最大异或和

    在我们得到的线性基中,从高位到低位用贪心贪掉每一个元素,如果异或了这个元素变大就异或他。

        LL ans=0;
        for(int i=62;i>=0;i--)
            if((ans^p[i])>ans)ans^=p[i];
    

    查询某个数

    我们也是从低到高扫这个数的每一位,如果这第 i 位为 1,就异或上 Pi,然后知道处理到最后一位。如果变成 0 了,那么就是可以的。

    bool check(int x)//查询能否异或成某个数
    {
        for(int i=31;i>=0;i--)
        {
            if(x>>i)x^=p[i];
        }
        return x==0;
    }
    

    线性基求交

    有一道模板题,不过要用到线段树来优化查询
    题目链接:https://ac.nowcoder.com/acm/contest/884/B

    #include<bits/stdc++.h>
    using namespace std;
    const int maxx=5e4+10;
    int a[maxx<<2][32];
    void insert(int x,int temp)//构造线性基
    {
        for(int i=31;i>=0;i--)
        {
            if(x>>i)
            {
                if(!a[temp][i])
                {
                    a[temp][i]=x;
                    break;
                }
                x^=a[temp][i];
            }
        }
    }
    bool check(int x,int temp)//查询能否异或成某个数
    {
        for(int i=31;i>=0;i--)
        {
            if(x>>i)x^=a[temp][i];
        }
        return x==0;
    }
    void pushup(int temp)//线性基求交
    {
        int t1[32],t2[32],l=temp*2,r=temp*2+1;
        for(int i=0;i<32;i++)
            t1[i]=t2[i]=a[l][i];
        for(int i=0;i<32;i++)
        {
            if(a[r][i])
            {
                int x=a[r][i],t=0;
                for(int j=31;j>=0;j--)
                {
                    if(x>>j)
                    {
                        if(!t1[j])
                        {
                            t1[j]=x,t2[j]=t;
                            break;
                        }
                        x^=t1[j],t^=t2[j];
                    }
                }
                if(!x)insert(t,temp);
            }
        }
    }
    void build(int l,int r,int temp)
    {
        if(l==r)
        {
            int s,t;
            scanf("%d",&s);
            while(s--)
            {
                scanf("%d",&t);
                insert(t,temp);
            }
            return;
        }
        int mid=(l+r)/2;
        build(l,mid,temp*2);
        build(mid+1,r,temp*2+1);
        pushup(temp);
    }
    bool query(int l,int r,int p,int q,int x,int temp)
    {
        if(p<=l&&r<=q)
        {
            return check(x,temp);
        }
        int mid=(l+r)/2;
        bool res=1;
        if(p<=mid)res&=query(l,mid,p,q,x,temp*2);
        if(q>mid)res&=query(mid+1,r,p,q,x,temp*2+1);
        return res;
    }
    int main()
    {
        int n,m;
        cin>>n>>m;
        build(1,n,1);
        int p,q,x;
        while(m--)
        {
            scanf("%d%d%d",&p,&q,&x);
            if(query(1,n,p,q,x,1))printf("YES
    ");
            else printf("NO
    ");
        }
        return 0;
    }
    
  • 相关阅读:
    截取文件路径组成新文件路径
    jsoup选择器
    正则小示例
    一个没有经过优化的过滤指定目录下的指定扩展名文件的算法
    正则表达式生成问题
    链接中带换行的页面查找替换问题
    数组扩容测试
    LeetCode 3.无重复字符的最长子串
    LeetCode 200.岛屿数量
    LeetCode 560.和为K的子数组
  • 原文地址:https://www.cnblogs.com/HooYing/p/11349578.html
Copyright © 2011-2022 走看看