首页 > 代码库 > 【HDU3949】XOR 线性基

【HDU3949】XOR 线性基

#include <stdio.h>
int main()
{
	puts("转载请注明出处谢谢");
	puts("http://blog.csdn.net/vmurder/article/details/43448493");
}


题意:给若干个数让你异或,然后询问第k大的异或和。


题解:

先搞出来线性基,然后第k大的异或和就是:

把k二进制拆分,第i位上有1,就把第i个线性基异或进来。

原因:

因为线性基是一堆高位上的1(或许有一些位动不了),然后把这样每一位可以填0/1,跟二进制差不多。

自己脑补去吧。


……我在说什么啊,我明白但是懒得写了。别管了,扒代码或者留言神马的吧。


经验之谈:

最开始写的是这份代码(WA):

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 10100
using namespace std;
int n,m;
unsigned long long a[N],ins[70];
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=63;k>j;k--)
					if((ins[k]>>j)&1)
						ins[k]^=ins[j];
				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]);
		sort(a+1,a+n+1);
		EX_Ins(n);
		for(m=i=0;i<=63;i++)
		{
			if(ins[i])ins[m++]=ins[i];
		}
		for(scanf("%d",&n);n--;)
		{
			scanf("%llu",&k);
			if(flag)k--;
			if(k>>m)puts("-1");
			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;
}

它WA了,请看这组数据:

1
3
77 89 53 
1
7

为什么会WA呢?

我维护线性基的方法是先排个序从大到小往里面加,

然后这样出来一个线性基时就再对之前的线性基进行修改、、

然后就WA了。


貌似有理有据,但是错在了哪里呢?


嗯,一个大的数A可能被之前某个线性基异或一下,变成比之后的数更小的数了,

于是它的最高位上有个1,

然后之后某个初始值小的数B成为了线性基,但是它在数A那个线性基的那一位上有1,

然后自然就挂了~~


询问时就会有3<2的情况了(ins[1]^ins[2]<ins[2])

诶,233。


AC代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 10100
using namespace std;
int n,m;
unsigned long long a[N],ins[70];
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]);
	//	sort(a+1,a+n+1);
		EX_Ins(n);
		for(m=i=0;i<=63;i++)
		{
			if(ins[i])ins[m++]=ins[i];
		}
		for(scanf("%d",&n);n--;)
		{
			scanf("%llu",&k);
			if(flag)k--;
			if(k>>m)puts("-1");
			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;
}


【HDU3949】XOR 线性基