2x < 2^(n+1),所以2x / 2^n 不是1就是0,2x % 2^n,就是第n位为0.
2x最多n位,其实就是把2x的最高位移到最后一位。这个操作简称左移。
其实所有数异或起来再左移和左移以后再异或是一样的。。。
对手可以把x左移的时刻有m+1个。(0,1,2,3....m)
如果对手把x 在i时刻左移。
就相当与把a1 - ai个数左移以后异或的值再异或ai+1 到am;
所以这m+1个时刻,可以看成m+1个x可以异或的数。
第i个数等于a1 - ai个数左移以后异或的值再异或ai+1 到am。
然后把这m+1个数建一个trie数,
就相当与找一个数x与m+1个数分别异或的最小值最大。
从上往下dfs,想要结果最优。
如果trie上某个节点有1,0两个儿子,我们的x无论这一位取1还是0,都不能产生贡献(异或,相同为0)。两个儿子,dfs下去。如果这个节点只有1 一个儿子,那么我们让x这一位取0. 向儿子1,dfs下去。
如果这个节点只有0 一个儿子,那么我们让x这一位取1. 向儿子0,dfs下去。
如果到叶子节点,ans 大于已知最大值,把最大值赋为ans,个数等于1;
如果到叶子节点,ans 等于于已知最大值,个数加1;
#include<bits/stdc++.h>
using namespace std;
int a[100005], b[100005], ha[100005], he, tot, ans1, tr[2000005][2], ma;
void read(int &x)
{
x = 0; int f = 0; char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-') f = 1; c = getchar();
}
while(c >= '0' && c <= '9')
{
x = 10 * x + c - '0'; c = getchar();
}
if(f) x = -x;
}
int n,m;
int zhuan(int x)
{
x = x << 1;
if(x >> n & 1)
{
x ^= he; x += 1;
}
// int hehe = (long long)(x << 1) / he;
//int haha = (long long)hehe + ((he - 1) & (x << 1));
return x;
}
void build(int x)
{
int nd = 0;
for(int i = n-1; i >= 0; i-- )
{
int haha = (x >> i) & 1;
if(tr[nd][haha] == 0)
tr[nd][haha] = ++tot;
nd = tr[nd][haha];
}
}
void dfs(int nd, int dep, int ans)
{
if(dep == -1)
{
if(ans > ma)
{
ma = ans; ans1 = 1;
}
else if(ans == ma) ans1++;
return ;
}
if(tr[nd][1] != 0 && tr[nd][0] != 0)
{
dfs(tr[nd][0],dep-1,ans); dfs(tr[nd][1],dep-1,ans);
}
else if(tr[nd][1] != 0)
dfs(tr[nd][1], dep-1, ans + (1 << dep));
else
dfs(tr[nd][0], dep-1, ans + (1 << dep));
}
int main()
{
//freopen("big.in","r",stdin);
//freopen("big.out","w",stdout);
read(n); read(m);
he = 1 << n;
for(int i = 1; i <= m; i++)
{
read(a[i]);
}
for(int i = m; i >= 1; i--)
ha[i] = ha[i+1] ^ a[i];
for(int i = 1; i <= m; i++)
{
a[i] = a[i] ^ a[i-1];
b[i] = zhuan(a[i]);
}
for(int i = 0; i <= m; i++)
b[i] = b[i] ^ ha[i+1];
for(int i = 0; i <= m; i++)
{
build(b[i]);}
int nd = 0;
dfs(0,n-1,0);
cout << ma << endl;
cout << ans1 << endl;
return 0;
}