1. 程式人生 > >線性基模板題hdu3949

線性基模板題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;

}