2022“杭电杯”中国大学生算法设计超级联赛(4)

比赛链接

2022“杭电杯”中国大学生算法设计超级联赛(4)

给一个数组 \(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;
}
posted @ 2022-07-30 01:11  zyy2001  阅读(56)  评论(0编辑  收藏  举报