2022“杭电杯”中国大学生算法设计超级联赛(4)
比赛链接
2022“杭电杯”中国大学生算法设计超级联赛(4)
7184. Link is as bear
给一个数组 \(a_{i}(1 \leq i \leq n)\)(保证至少存在两数相等) ,可以对数组进行操作:每次选定两个整数 \(l, r(1 \leq l \leq r \leq n)\), 令所有 \(a_{i}=x o r(a[l], \ldots, a[r])\) ,在进行任意操作后要让数组中所有数相同,请问这个数的相同值最大是多少
解题思路
线性基
结论:题目等价于从中选取任意数使得异或和最大,即线性基板子
证明:先证明出现两个连续的 \(0\) 可以构造出所有方案:例如 \(0,0,a_1,a_2\),我们总是可以对 \(a_1\) 和 \(a_2\) 删除或保留,而且还可以两边扩展,即可以形成线性基的方案。假设要保留的数为 \(1\),删除的数为 \(0\),如果出现连续的 \(0\),以 \(001\) 为例,可以先将前两个删除的数变为一个数,然后再次删除即出现连续的 \(0\),即可以构造出任意方案;如果出现连续的 \(1\),以 \(110\) 为例,可以先将前两个数异或,保留第一个数,后两个数两次异或使其出现连续的 \(0\) 也可满足要求;最后就剩 \(0101\dots\) 或 \(1010\dots\) 这种情况,由于至少存在两个相等的数,假设其值出现在方案中,则两个数中的任一个数的位置都可以为 \(0\) 或 \(1\),否则不出现在方案中的话两个位置都可以同时为 \(0\) 或 \(1\)(为 \(1\) 是两个相等的数异或对答案不影响)
- 时间复杂度:\(O(50n)\)
代码
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=1e5+5;
int t,n;
LL a[N];
int main()
{
for(scanf("%d",&t);t;t--)
{
cin>>n;
for(int i=0;i<n;i++)scanf("%lld",&a[i]);
int k=0;
for(int i=49;i>=0;i--)
{
for(int j=k;j<n;j++)
if(a[j]>>i&1)
{
swap(a[k],a[j]);
break;
}
if(!(a[k]>>i&1))continue;
for(int j=0;j<n;j++)
if(j!=k&&(a[j]>>i&1))a[j]^=a[k];
k++;
}
LL res=0;
for(int i=0;i<k;i++)res^=a[i];
printf("%lld\n",res);
}
return 0;
}