牛客网训练赛26D(xor)

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

链接: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;
                }
                else
                {
                    a[i]^=p[j];
                }
            }
        }
    }
    //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;
}

猜你喜欢

转载自www.cnblogs.com/caijiaming/p/9609807.html