线性基模板题hdu3949

hdu3949 XOR

题目大意:

就是给你长度为N的学列,有Q次查询,每次查询这写序列中能异或出来的第k小的值

解题思路 :

本题是一个线性基的入门题。 

其实线性基的求解过程就是一个高斯消元,它构建了一个二维的空间,N*bits这么大, 

通过列与列相消,求解出基向量也就是空间的极大无关组,通过这几个元素能得到含盖空间中所有元素的无关组.

本题求的就是这个无关组能构建出来的第K小的值.

求这个值我们可以类比最理想情况下的无关组,

1 0 0 0 0 0 … 0 p1

0 1 0 0 0 0 … 0 p2

… 

0 0 0 0 0 0 … 0 pn

那么对于第K小的值就是将K二进制展开,第i位上为1,就在结果上异或pni就好了

代码:

#include <cstdio>

#include <cstring>

#include <iostream>

#include <algorithm>

using namespace std;

int n,m;

unsigned long long a[10005],ins[100];



bool flag;



void EX_Ins(int n)

{

    int i,j,k;

    flag=0;

    memset(ins,0,sizeof ins);

    for(i=n;i;i--)

    {

        for(j=63;~j;j--)if((a[i]>>j)&1)

        {

            if(!ins[j])

            {

                ins[j]=a[i];

                for(k=0;k<63;k++)

                    for(int r=k+1;r<=63;r++)

                        if((ins[r]>>k)&1)

                            ins[r]^=ins[k];

                break;

            }

            else a[i]^=ins[j];

        }

        if(!a[i])flag=1;

    }

    return ;

}

int main()

{

    //freopen("test.in","r",stdin);

    int i,g,_g;

    unsigned long long k;

    for(scanf("%d",&_g),g=1;g<=_g;g++)

    {

        printf("Case #%d:\n",g);

        scanf("%d",&n);

        for(i=1;i<=n;i++)scanf("%llu",&a[i]);

        //下面四行完成线性基的操作

        EX_Ins(n);

        for(m=i=0;i<=63;i++)

        {

            if(ins[i])ins[m++]=ins[i];

        }



//        for(i=0;i<=m-1;i++)

//            cout<<ins[i]<<endl;





        for(scanf("%d",&n);n--;)

        {

            scanf("%llu",&k);

            if(flag)k--; //flag是1,说明有0

            if(k>>m)puts("-1");//共能组成2的M次方个,如果k更大,那就impossible

            else {

                unsigned long long ret=0;

                for(i=0;i<m;i++)//(原理是从低位开始一位一位异或上去)

                if((k>>i)&1)

                    ret^=ins[i];

                printf("%llu\n",ret);

            }

        }

    }

    return 0;

}

猜你喜欢

转载自blog.csdn.net/pcfbyssz/article/details/81388663