你需要在[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
*/