1. 程式人生 > >【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;
}