解题报告 一姬的三倍满自动机

本文介绍了一种设计三倍满自动机的方法,以确保在麻将游戏中不会出现玩家被飞的情况。核心问题是寻找三个非负整数a[i]的异或和最大值,其中考虑了异或运算和给定的非负整数x。通过分析和样例,提出了利用 Trie 树存储数字,并结合x的二进制位进行计算的策略,得出另一位必须为(u^ v ^1)才能最大化异或和。

题目描述

一姬想要设计一种机器,使自己不断地和牌上分,但是她觉得麻将是可以让四个人都得到快乐的,至少她不希望雀魂玩家减一这种事情的发生。因此她不希望有人被飞,所以她想要你设计一款三倍满自动机,使得自己在闲家和牌收益最大又不会让人被飞。
由于她只和三倍满,所以做出决策以及提高打点是十分重要的,在自动机中,这需要解决以下问题实现:
给定n个非负整数 a1a_1a1,a2a_2a2,a3a_3a3,a4a_4a4… ,给定一个非负整数x,求a[i]a[i]a[i]⨁\bigoplusa[j]a[j]a[j] ⨁\bigoplusxxx的最大值,其中 ⨁\bigoplus表示异或运算。
输入格式
第一行一个正整数nnn和一个非负整数xxx

第二行nnn个非负整数表示aia_iai

输出格式
输出一行一个非负整数表示答案。

样例
样例输入
3 4
3 5 7
样例输出
6
数据范围与提示
2≤\leqnnn≤\leq10610^6106
0≤\leqaia_iai≤\leq10910^9109
0≤\leqxxx≤\leq10910^9109


分析

这道题求的是三个数的异或和,那么自然而然地可以联系到
The XOR Largest Pair这道题,不同的是,我们要求两个数再异或x的最大值
在那道题中,我们把每个数的二进制表示存入Trie树中,并从高位到低位枚举每个位,如果存在当前数字^1的数,就可以为答案做贡献
比如:当前为1,同一层还有一个0,那么两者异或后当前位就为1
本题也可以用类似思路,不过要把x的当前位参与进来

具体的,用u表示当前位,v表示x的当前位
1.u=1,v=1,1^1=0,则另一位为1,使得0 ^1=1
2.u=1,v=0,1^0=1,则另一位为0,使得1 ^0=1
3.u=0,v=0,0^0=0,则另一位为1,使得0 ^1=1

综上得,我们可以发现,另一位必须是(u^ v ^1),才能为当前做贡献


Code:

#include<cstdio>
#include<iostream>
using namespace std;
#define int long long
int n,x,a[10000005],t[50000005][2],cnt=1,Ans;
void build(int c)//Trie的push操作
{
	int p=1;
	for(int i=31;i>=0;i--)
	{
		int b=((c>>i)&1);
		if(!t[p][b])
		{
			t[p][b]=++cnt;
		}
		p=t[p][b];
	}
}
void search(int c,int ans)
{
	int p=1;//注意,每次是从根节点开始跑!
	for(int i=31;i>=0;i--)
	{
		int b=((c>>i)&1);//u
		int o=b^((x>>i)&1)^1;//另一位
		if(t[p][o])
		{
			p=t[p][o];
			ans+=(1<<i);
		}
		else{
			p=t[p][o^1];
		}
	}
	Ans=max(Ans,ans);
}
signed main()
{
	scanf("%lld%lld",&n,&x);
	//build(x);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		build(a[i]);
		search(a[i],0);
	}
	printf("%lld",Ans);
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值