Codeforces Round532 题解

题目传送门

视频题解戳这里,超级详细的视频题解哦,从读题到AC的全过程,还有写代码的过程哦!

这里我只写了F题的题解,其他的都在视频题解里面

F题的题意就是给定区间,求区间中任选几项异或的最大值。有q组询问。

拿到这个题目,因为是一道区间询问的题目,就感觉像是数据结构,然而不知道什么数据结构能解决它。
下面我就带着大家来分析一下。

我们要求异或的最大值,那么我们就需要知道什么情况下a XOR b > a和b ,不要想复杂了,其实a和b二进制中最高位1的位置不同,那么就可以保证a XOR b > a和b了。
我们就从这个角度去思考这个问题。我们只需要知道序列中每一个数的最高位1出现在哪里就可以了,我们就可以直接判断它在不在区间[l,r]中,然后我们就可以不断得到最大值。
如何求序列中每一个元素得最高位1在序列中得位置呢,我们需要一个新的知识,就是线性基,如果大家知道线性基,那么这个问题就很简单了。如果不知道,那么这里有两篇博客大家可以看一下:线性基讲解1线性基讲解2

现在我们已经知道了线性基了,我们就可以很容易得求出最高位1在序列中的位置了。
现在还有一个问题,这个题目是q次询问,我们就需要预处理,pos[i][j]表示到序列中第i个为止,最高位1出现在第j位的位置,举个例子:pos[5][7] = 5,那么a[5]就是序列中二进制最高位第7位是1的数。p[i][j]表示序列中到i为止,最高位j为1的数值,p[5][7] = 128,表示a[5] = 128。

那么我们在询问区间的时候,我们对于右端点r来说,只要pos[r][j]>=l,就表示满足条件的数在区间内,我们就异或起来。不断更新最大值。
复杂度线性O(n)。
下面是代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5+7;
int p[maxn][21],pos[maxn][21];
int a[maxn];
int n;
int main()
{	
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",a+i);
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=20;j>=0;j--)
		{
			p[i][j] = p[i-1][j];
			pos[i][j] = pos[i-1][j];
		}
		int tpos = i;
		for(int j=20;j>=0;j--)
		{
			if((a[i]>>j)&1)
			{
				if(!p[i][j])
				{
					p[i][j] = a[i];
					pos[i][j] = tpos;
					break;
				}
				if(pos[i][j]<tpos)
				{
					swap(p[i][j],a[i]);
					swap(pos[i][j],tpos);
				}
				a[i] ^= p[i][j];
			}
		}
	}
	int q;
	scanf("%d",&q);
	for(int i=1;i<=q;i++)
	{
		int l,r;
		scanf("%d%d",&l,&r);
		int ans = 0;
		for(int j=20;j>=0;j--)
		{
			if(pos[r][j]>=l) ans = max(ans,(ans^p[r][j]));
		}
		printf("%d\n",ans);
	}
	return 0;
}

如果有不明白的地方,欢迎评论私信或者直接去看视频讲解哦!

猜你喜欢

转载自blog.csdn.net/KIKO_caoyue/article/details/86491732