zoukankan      html  css  js  c++  java
  • 牛客网训练赛26D(xor)

    题目链接:https://www.nowcoder.com/acm/contest/180/D

    线性基的学习:https://www.cnblogs.com/vb4896/p/6149022.html

    链接:https://www.nowcoder.com/acm/contest/180/D
    来源:牛客网

    时间限制:C/C++ 1秒,其他语言2秒
    空间限制:C/C++ 262144K,其他语言524288K
    64bit IO Format: %lld

    题目描述

    小a有n个数,他提出了一个很有意思的问题:他想知道对于任意的x, y,能否将x与这n个数中的任意多个数异或任意多次后变为y

    输入描述:

    第一行为一个整数n,表示元素个数
    第二行一行包含n个整数,分别代表序列中的元素
    第三行为一个整数Q,表示询问次数
    接下来Q行,每行两个数x,y,含义如题所示

    输出描述:

    输出Q行,若x可以变换为y,输出“YES”,否则输出“NO”
    示例1

    输入

    复制
    5
    1 2 3 4 5
    3
    6 7 
    2 1
    3 8

    输出

    复制
    YES
    YES
    NO

    说明

    对于(6,7)来说,6可以先和3异或,再和2异或
    对于(2,1)来说,2可以和3异或
    对于(3,8)来说,3不论如何都不能变换为8

    备注:

    对于100%的数据,n,Q<=10
    5

    保证所有运算均在int范围内

    思路:看了题解,是线性基的最基础的题,第一次听到线性基,根本不知道是什么,然后百度学了一下,学习博客:https://www.cnblogs.com/vb4896/p/6149022.html
    线性代数中 有极大线性无关组和空间的基的概念。线性基的性质于此类似
    如果把一个数转化为二进制,对应成一个由0和1构成的向量,所有的这些向量就构成了一个向量空间。 原问题就转化为求这个向量空间的极大线性无关组,把这样一个极大线性无关组称为线性基,线性基的求法代码中有
    基本思想:从左往右扫描每个向量,对于第i个向量的第j位,如果前面已经有第j位为1的向量,那么把第i个向量异或那个向量,如果没有的话,直接存储下来,这样最后得到的向量组,不考虑0向量,最高位的1的位置是互不相同的,显然
    这些向量线性无关,于是就构造出了极大线性无关组,也就是线性基。
    那么说一下这一题的思路,先求出线性基,要寻找能否转化为x,则从x的最高位往低位判断,假设当前x的这一位是1,如果线性基中存在某个向量最高位的1在这一位,那么这个向量肯定要取,把x异或这个向量,否则没法组合出来
    看代码:
    #include<iostream>
    #include<string.h>
    #include<map>
    #include<cstdio>
    #include<cstring>
    #include<stdio.h>
    #include<cmath>
    #include<ctype.h>
    #include<math.h>
    #include<algorithm>
    #include<set>
    #include<queue>
    typedef long long ll;
    using namespace std;
    const ll mod=1e9+7;
    const int maxn=1e5+10;
    const int maxk=5e3+10;
    const int maxx=1e4+10;
    const ll maxe=1000+10;
    #define INF 0x3f3f3f3f3f3f
    #define Lson l,mid,rt<<1
    #define Rson mid+1,r,rt<<1|1
    int a[maxn],p[maxn];//p是用来
    int n,q;
    void guass()//求线性基的函数,其实就是最大线性无关组
    {
        memset(p,0,sizeof(p));//每一个数转化成二进制情况下看做一个线性组,每一位看做线性组的每一个元素
        for(int i=0;i<n;i++)
        {
            for(int j=62;j>=0;j--)
            {
                if((a[i]>>j)&1)
                {
                    if(!p[j])
                    {
                        p[j]=a[i];
                        break;//这里为什么直接break呢?  因为a[i]已经直接赋值了,肯定不能再用了,不然就会有两个向量异或起来等于0 了
                    }
                    else
                    {
                        a[i]^=p[j];//为什么要把a[i]给变掉呢?因为要最终得到的线性基是最高位的1的位置是互不相同的
                    }
                }
            }
        }
        //for(int i=0;i<=62;i++) if(p[i]) r++;
    }
    int query(int x)
    {
        for(int i=62;i>=0;i--)
        {
            if((x>>i)&1)
            {
                if(!p[i]) return 0;
                x^=p[i];
            }
        }
        if(x==0) return 1;
        else return 0;
    }
    int main()
    {
        cin>>n;
        for(int i=0;i<n;i++) cin>>a[i];
        guass();
        cin>>q;
        while(q--)
        {
            int x,y;
            cin>>x>>y;
            if(query(x^y)) cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
        }
        return 0;
    }
    当初的梦想实现了吗,事到如今只好放弃吗~
  • 相关阅读:
    Android自定义Dialog
    Ubuntu中好用的中文输入法
    Android_去掉EditText控件周围橙色高亮区域
    Android中Bitmap,byte[],Drawable相互转化
    准备期末考试 博客不更了
    NYOJ5 Binary String Matching ——KMP
    hdu1420 Prepared for New Acmer ——快速幂
    点头1010 只包含因子2 3 5的数
    Constructing Roads ——最小生成树
    hdu1257 最少拦截系统 ——DP么?
  • 原文地址:https://www.cnblogs.com/caijiaming/p/9609807.html
Copyright © 2011-2022 走看看