BZOJ 3689: 异或之 字典树 优先队列

版权声明:想转就转吧,注明出处就行 括弧笑 https://blog.csdn.net/BlackJack_/article/details/76066498

3689: 异或之

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 398  Solved: 184
[Submit][Status][Discuss]

Description

给定n个非负整数A[1], A[2], ……, A[n]。
对于每对(i, j)满足1 <= i < j <= n,得到一个新的数A[i] xor A[j],这样共有n*(n-1)/2个新的数。求这些数(不包含A[i])中前k小的数。
注:xor对应于pascal中的“xor”,C++中的“^”。

Input

第一行2个正整数 n,k,如题所述。
以下n行,每行一个非负整数表示A[i]。

Output

 共一行k个数,表示前k小的数。

Sample Input

4 5
1
1
3
4

Sample Output

0 2 2 5 5

HINT

【样例解释】
1 xor 1 = 0 (A[1] xor A[2])
1 xor 3 = 2 (A[1] xor A[3])
1 xor 4 = 5 (A[1] xor A[4])
1 xor 3 = 2 (A[2] xor A[3])
1 xor 4 = 5 (A[2] xor A[4])
3 xor 4 = 7 (A[3] xor A[4])
前5小的数:0 2 2 5 5
【数据范围】
 对于100%的数据,2 <= n <= 100000; 1 <= k <= min{250000, n*(n-1)/2};
        0 <= A[i] < 2^31


对二进制字典树维护一下size

就可以求异或K大值啦

中间过程用priority_queue搞搞就可以啦

再注意一下 题中 (x xor y) 和 (y xor x) 是同一种方案就好了


刚看完题 以为是线性基。。。开心打完以后才发现读错题。。。

重新YY一下 trie树+优先队列秒掉

先附赠线性基求前K小值。。。

#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<complex>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=100100;

int n,m,z,a[N];

void guass()
{
	register int i,j,k=0;
	for(j=30;j>=0;j--)
	{
		for(i=k+1;i<=n;++i)if(a[i]&(1<<j))break;
		if(i>n)continue;k++;swap(a[i],a[k]);
		for(i=1;i<=n;++i)if(i!=k&&(a[i]&(1<<j)))a[i]^=a[k];
	}
	z=n-k;n=k;
}

inline query_kth(int k)
{
	register int res=0,i;
	for(i=n;i>=1;i--)if(k&(1<<(i-1)))res^=a[i];
	return res;
}

int main()
{
	n=read();m=read()-1;
	register int i,j,k,tmp;
	for(i=1;i<=n;++i)a[i]=read();
	guass();
	for(i=1;i<=(n>>1);++i)swap(a[i],a[n-i+1]);
	i=tmp=0;k=0;j=z;
	while(i<m)
	{
		if(!j){tmp=query_kth(++k);print(tmp);putchar(' ');j=z;}
		else {print(tmp);putchar(' ');j--;}
		i++;
	}
	j?print(tmp):print(query_kth(++k));
	puts("");return 0;
}
/*
4 5
1 1 3 4

0 2 2 5 5
*/

正解

#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<complex>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=100100;

int n,m,root,cnt,a[N];

struct trie{int ls,rs,sz;}tr[N<<5];

struct node
{
	int rk,key,val;
	friend bool operator <(const node &x,const node &y){return x.val>y.val;}
};

void insert(int &k,int pos,int x)
{
	if(!k)k=++cnt;
	tr[k].sz++;if(!(~pos))return ;
	x&(1<<pos)?insert(tr[k].rs,pos-1,x):insert(tr[k].ls,pos-1,x);
}

inline int query_kth(int x,int rk)
{
	register int pos=30,res=0,k=root;
	while(~pos)
	{
		if(x&(1<<pos))
		{
			if(tr[tr[k].rs].sz>=rk)k=tr[k].rs;
			else rk-=tr[tr[k].rs].sz,k=tr[k].ls,res+=1<<pos;
		}
		else
		{
			if(tr[tr[k].ls].sz>=rk)k=tr[k].ls;
			else rk-=tr[tr[k].ls].sz,k=tr[k].rs,res+=1<<pos;
		}
		pos--;
	}
	return res;
}

priority_queue<node>q;

int main()
{
	n=read();m=read();
	register int i;
	for(i=1;i<=n;++i)a[i]=read();
	for(i=1;i<=n;++i)insert(root,30,a[i]);
	node tmp;
	for(i=1;i<=n;++i){tmp.key=a[i];tmp.rk=2,tmp.val=query_kth(a[i],2);q.push(tmp);}
	for(i=1;i<=(m)<<1;++i)
	{
		tmp=q.top();q.pop();
		if(i&1)print(tmp.val),putchar(' ');
		if(tmp.rk<=n)
		{
			tmp.rk++;tmp.val=query_kth(tmp.key,tmp.rk);
			q.push(tmp);
		}
	}
	puts("");//print(q.top().val);
	return 0;
}
/*
4 5
1 1 3 4

0 2 2 5 5
*/

阅读更多
换一批

没有更多推荐了,返回首页