【loj114】k大異或和 線性基+特判

題目描述

給由 $n​$ 個數組成的一個可重集 $S​$ ,每次給定一個數 $k​$ ,求一個集合 $T⊆S​$ ,使得集合 $T​$ 在 $S​$ 的所有非空子集的不同的異或和中,其異或和 $T_1\ \text{xor}\ T_2\ \text{xor}\ …\ \text{xor}\ T_{|T|}​$ 是第 $k​$ 小的。求這個第 $k$ 小的異或和。


題解

線性基+特判

板子題沒什麼好說的,直接求出嚴格線性基,由於每個最高位只有一個因此按位判斷即可。

關鍵在於一個特判:原來的可重集可能能夠組成0,也可能不能夠組成0,需要判斷一下0是否算在內。

時間複雜度 $O(n\log n)$ 

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
ll a[100010] , tot;
int main()
{
	int n , m , i , flag = 0;
	ll j , ans;
	scanf("%d" , &n);
	for(i = 1 ; i <= n ; i ++ )
	{
		scanf("%lld" , &a[i]);
		if(a[i] == 0) flag = 1;
	}
	for(j = 1ll << 49 ; j ; j >>= 1)
	{
		for(i = tot + 1 ; i <= n ; i ++ )
			if(a[i] & j)
				break;
		if(i > n) continue;
		swap(a[i] , a[++tot]);
		for(i = 1 ; i <= n ; i ++ )
			if(i != tot && a[i] & j)
				a[i] ^= a[tot];
	}
	for(i = 1 ; i <= n ; i ++ )
		if(a[i] == 0)
			flag = 1;
	scanf("%d" , &m);
	while(m -- )
	{
		scanf("%lld" , &j) , j -= flag;
		if(j >= 1ll << tot) puts("-1");
		else
		{
			ans = 0;
			for(i = 1 ; i <= tot ; i ++ )
				if(j & (1ll << (tot - i)))
					ans ^= a[i];
			printf("%lld\n" , ans);
		}
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章