D. Vitya and Strange Lesson

题目1

题意:

    给出一组序列,有q次访问,每次访问输入一个x,每次对这组序列异或x,然后输出最小未出现的元素。注意每次访问后数组都会改变。

分析:

    由于异或具有结合律,所以不需要每次去改变序列。如何求最小未出现过的元素呢,由于x^y=z,若知道y和z,则x就是固定的。y就是每次的访问,z是答案,因为z不是原数组异或y产生的,所以x必然未在原数组中。所以答案是由未在数组中的元素决定的。所以我们可以用那些未出现过的元素,求他们与x异或的最小值。这样就是用字典树就可以了。
    注意这些元素最多可以取到2倍的定义域。证明:若x大于定义域,那么答案显然为0,且x不可能超过定义域的两倍。若x在定义域内,答案也在定义域内,那么所对应的那个不在数组中的值至多是定义域的两倍。

#include <iostream>
using namespace std;

int tire[600005*20][2],tot = 1; 
int num[600005]; 

void insert(int a)
{
	int rt = 0;
	for (int i = 19; i >= 0; i--)
	{
		int t = (a>>i) & 1;
		if( tire[rt][t] == 0 )
		{
			tire[rt][t] = tot ++;
		}
		rt = tire[rt][t];
	}
}

int query(int q)
{
	int res = 0,rt = 0;
	for (int i = 19; i >= 0; i--)
	{
		int t = (q >> i) & 1;
		if( tire[rt][t] == 0 )
		{
			res += (1<<i);
			rt = tire[rt][t^1];
		}else rt = tire[rt][t];
	}
	return res;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		int x;
		cin >> x;
		num[x] = 1;
	}
	for (int i = 0; i <= 600000; i++)
	{
		if( !num[i] ) insert(i);
		//cout << i << " Asd" << tot << '\n';
	}
	int q = 0;
	for (int i = 1; i <= m; i++)
	{
		int x;
		cin >> x;
		q ^= x;
		cout << query(q) << '\n';
	}
	return 0;
}

发布了103 篇原创文章 · 获赞 6 · 访问量 7021

猜你喜欢

转载自blog.csdn.net/weixin_44316314/article/details/104731807
今日推荐