HDOJ 3949 XOR (高斯消元 + XOR线性基)

来源:互联网 发布:淘宝网店项目战略目标 编辑:程序博客网 时间:2024/05/30 23:00


点击打开链接


题意:给出n个数,任选大于等于1个数进行异或,得到的结果加入一个集合,问这个集合中第k大的数是多少?


异或类比加减,把n个数的二进制从上到下排成一个矩阵,化成行最简式(每一行的第一个1所在的列上只有这一个1)。那么非零的行所对应的数,是原来那n个数的极大无关组。极大无关组的定义是:线性无关和原来的数都可以由极大无关组中的数来表示。行最简式显然线性无关,并且原来这么得到行最简式的现在就可以怎么回去,一定是可以表示出原来那些数的。化成行最简式的伪代码如下:

for i = 所有数

{

p = i中1所在的最高位

for j = 所有数

if i != j && j中1所在的最高位也为p

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

}

其中内层a[j]改了, 外层循环时也会改变。

为了便于把都是0的行给去掉,一开始我们不要把数拆分成二进制,而是预处理一个数组,数组的第k个数表示2^k次方。倒着循环,如果i大于等于的第一个 ak,那么最高位就在第k个位置。是不是在p,用&,根据与运算的特点考虑。如果不用&,就会TLE。

把a从大到小排序,去掉0后,如果还有num个数,num<n,表示原来的数可以异或得到0,因为有重复的。这里需要特判。所以第k大的数相对来说就是第k-1大的数了。

把k拆分成二进制,把是1的位对应的a累积异或。这个是找规律的,为了不越异或越小,所以之前化成行最简式,把最高位的1都错开。


#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#define N 10005typedef unsigned long long  LL;using namespace std;int T, n, q, k, cnt, tmp, t, num;LL  sum, s;LL a[N], p[N];void Gauss(){    for (int i = 1; i <= n; i++)    {        for (int j = 63; j >= 0; j--)            if (a[i]&p[j])            {                tmp = j;                break;            }        for (int j = 1; j <= n; j++)            if (j != i)            {                if (a[j] & p[tmp]) a[j] = a[j] ^ a[i];            }    }    sort(a+1, a+n+1);    t = 1;    while (a[t] == 0 && t <= n) t++;    num = n-t+1;}int main(){    scanf("%d", &T);    p[0] = 1;    for (int i = 1; i <= 63; i++) p[i] = 2 * p[i-1];    int w = 0;    while (T--)    {        w++;        printf("Case #%d:\n", w);        scanf("%d", &n);        for (int i = 1; i <= n; i++) scanf("%llu", &a[i]);        Gauss();        scanf("%d", &q);        for (int i = 1; i <= q; i++)        {            scanf("%d", &k);            if (num < n) k--;            if (k > p[num]-1 )            {                printf("-1\n");                continue;            }            cnt = 0;            sum = 0;            while (k > 0)            {                cnt++;                if (k & 1) sum = sum ^ a[cnt+t-1];                k = k / 2;            }            printf("%llu\n", sum);        }    }    return 0;}



0 0