bzoj 3689 异或之

二分答案+trie判定。卡时过

之后看题解:

用堆维护每个数可以获得的最小答案,每次取出最小元素,查询它的比当前大的最小值,加入堆。就和dijstra求k短路差不多的思路。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>

#define ll long long
#define eps 1e-10
#define md
#define N 4000010
using namespace std;
int sz[N],ch[N][2],q[N];
int cnt=0,X,n,K,w=0;
int a[100010];
const int mxdep=30;
void insert(int &i,int dep,int dt)
{
	if (!i) i=++cnt;
	sz[i]++;
	//printf("insert %d %d %d\n",i,dep,sz[i]);
	if (dep<0) return;
	int t=(dt>>dep)&1;
	insert(ch[i][t],dep-1,dt);
}

int query(int i,int dep,int dt)
{
	//printf("query %d %d %d\n",i,dep,sz[i]);
	if (!i) return 0;
	if (dep<0) return sz[i];
	int t=(dt>>dep)&1; //printf("t %d %d %d %d\n",i,t,ch[i][0],ch[i][1]);
	if (X&(1<<dep)) return sz[ch[i][t]]+query(ch[i][t^1],dep-1,dt);
	else return query(ch[i][t],dep-1,dt);
}

bool ok(ll x)
{
	ll ans=0; X=x;
	for (int i=1;i<=n;i++) ans+=query(1,mxdep,a[i]);
	ans-=n; ans>>=1;
	//printf("%lld %lld\n",x,ans);
	return ans>=K;
}

void get(int i,int dep,int dt,int now)
{
	//printf("get %d [%d %d] %d %d %d\n",i,ch[i][0],ch[i][1],dep,dt,now);
	if (!i) return;
	if (dep<0)
	{
		for (int j=1;j<=sz[i];j++) q[++w]=now;
		//printf("__ %d : %d\n",now,sz[i]);
		return;
	}
	int t=(dt>>dep)&1;
	get(ch[i][t],dep-1,dt,now); get(ch[i][t^1],dep-1,dt,now|(1<<dep));
}
		
	
void solve(int i,int dep,int dt,int l,int now)
{
	//printf("solve %d %d %d\n",dt,dep,now);
	if (!i) return;
	if (dep<0)
	{
		for (int j=1;j<=sz[i];j++) q[++w]=now;
		//printf("__? %d : %d\n",now,sz[i]);
		return;
	}
	int t=(dt>>dep)&1;
	if ((l>>dep)&1) { get(ch[i][t],dep-1,dt,now); solve(ch[i][t^1],dep-1,dt,l,now|(1<<dep));}
	  else solve(ch[i][t],dep-1,dt,l,now);
}
	 
	
int main()
{
#ifndef ONLINE_JUDGE
	freopen("data.in","r",stdin); //freopen("data.out","w",stdout);
#endif
	scanf("%d%d",&n,&K);
	int root=0;
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		insert(root,mxdep,a[i]);
	}
	ll l=0,r=2147483647;
	while (l!=r)
	{
		 ll mid=(l+r)>>1;
		 if (ok(mid)) r=mid; else l=mid+1;
	}
	//printf(":%lld\n",l);
	K=(K<<1)+n; l--;
	for (int i=1;i<=n;i++) solve(1,mxdep,a[i],l,0);
	l++; while (w<=K) q[++w]=l;
	sort(q+1,q+K+1);
	for (int i=n+1;i<=K;i+=2) printf("%d ",q[i]); printf("\n");
	return 0;
}


你可能感兴趣的:(trie,二分)