[20190927机房测试] big

你需要在[0,2^n)中选一个整数 x,接着把 x 依次异或 m 个整数 a1~am
在你选出 x 后,你的对手需要选择恰好一个时刻(刚选完数时、异或一些数后或是最后)
将 x 变为【这里放不了公式,见下面】
你想使 x 最后尽量大,而你的对手会使 x 最后尽量小
你需要求出 x 最后的最大值,以及得到最大值的初值数量

上面的公式是:

[lfloor dfrac{2x}{2^n} floor mod 2^n ]

也就是二进制位向前移动一位,超过(2^n)的向0位补齐

看懂了这个公式,这题就是一个很简单的tire树基础题了

代码

#include<bits/stdc++.h>
#define N 100005
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
int n,m,a[N],pre[N],suf[N],ps[N];
int nxt[N*31][2],ndsum;
int ans=-1,num=0;

template <class T>
void read(T &x)
{
	char c;int sign=1;
	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
	while((c=getchar())>='0'&&c<='9') x=x*10+c-48; x*=sign;
}

int upsidedown(int x) { return ((2LL*x)/(1LL<<n)+2LL*x)%(1LL<<n); }
void ins(int x)
{
	int now=0;
	for(int i=n-1;i>=0;--i)
	{
		int c=(x>>i&1);
		if(!nxt[now][c]) nxt[now][c]=++ndsum;
		now=nxt[now][c];
	}
}
void dfs(int rt,int dep,int val)//在trie上dfs一次求max 
{
	if(!dep)//递归到了叶子 
	{
		if(ans==val) num++;
		else if(val>ans) {ans=val;num=1;}
		return;
	}
	if(!nxt[rt][0]) dfs(nxt[rt][1],dep-1,val^(1<<(dep-1)));
	else if(!nxt[rt][1]) dfs(nxt[rt][0],dep-1,val^(1<<(dep-1)));
	else
	{
		dfs(nxt[rt][1],dep-1,val);
		dfs(nxt[rt][0],dep-1,val);
	}
}
int main()
{
	freopen("big.in","r",stdin);
	freopen("big.out","w",stdout);
	read(n);read(m);
	for(int i=1;i<=m;++i) read(a[i]);
	for(int i=1;i<=m;++i) pre[i]=(pre[i-1]^a[i]);
	for(int i=m;i>=1;--i) suf[i]=(suf[i+1]^a[i]);
	for(int i=0;i<=m;++i) ps[i]=(upsidedown(pre[i])^suf[i+1]);
	//原问题转换成求(ps[i]^x)min的最大值
	for(int i=0;i<=m;++i) ins(ps[i]);
	dfs(0,n,0);
	cout<<ans<<endl<<num<<endl;
	return 0;
}
/*
10 30
24 54 878 11 36 46 7 8 654 65 46 54 654 65 46 46 47 7 651 321 132 654 44 55 231 5 587 89 46 88

30 3
1 2 3
*/
原文地址:https://www.cnblogs.com/tqr06/p/11599989.html