2023牛客九 G

        本题是博弈题,但是用到了线性基。

        首先来描述下博弈的部分,总共会有三个状态:赢,平,输。三者的权重高低从大到小,假设一方的下一个动作导致自己进入失败的状态,那么他可以通过复读上一个人的行为,来使集合元素不再增加。因此只有当第一次alice能赢或者alice无论选了哪两个数进行异或,bob选数都能与之异或达到k这两种情况有用,bob选数其中一个必须是alice异或产生的数字。

        第一个情况很好表现,只要set存一下就行了。时间是nlogn

        第二个如果你用暴力加二分寻找,那么时间复杂度会是n^2logn,必定超时。

        那么这里就要用到线性基。通过线性基的封闭性来求得。假设a\oplus b = c \oplus k,那么很显然

        \left ( a \oplus k \right ) \oplus \left ( b \oplus k \right ) = c \oplus k,原序列任意两个数的异或都可以由线性基得到,线性基的数量是固定的,是极大线性无关组,线性基能表示的数量为 2的线性基个数次方。两个元素异或的并集是线性基表示的数字的子集,同时也要是原来集合的子集。因此需要原来序列大小等于2的线性基个数大小。

        要经过去重操作,重复的数字加入线性基不会再增加线性基个数。

        有一说一我真的没搜到线性基的封闭性是什么东西,这也是第一次看到,如果有更深的理解之后再来修改。

        

#include<bits/stdc++.h>
#define ll long long
#define N 1000005
#define M 105
#define debug cout<<"~~debug "
#define rc p<<1|1
#define lc p<<1
#define PII pair<long long,long long>
#define pb push_back
#define Inf 0x3f3f3f3f
//neuro-sama
const ll mod = 1e9+7;
using namespace std;
inline int read()
{
	char c=getchar();int f=1,x=0;
	while(c>'9'||c<'0'){ if(c=='-') f=-f;c=getchar();}
	while(c<='9'&&c>='0'){x=(x<<3)+(x<<1)+c-'0';c=getchar();}
	return f*x;
}
int d[35],a[N];
int T,n,k;
void add(int x){//线性基的获取
	for(int i=31;i>=0;i--){
		if(1&(x>>i)){
			if(!d[i]){
				d[i]=x;
				break;
			}
			else x^=d[i];
		}
	}
}
void solve()
{
	memset(d,0,sizeof(d));
	cin>>n>>k;
	set<int>s;
	for(int i=0;i<n;i++){
		cin>>a[i];
		s.insert(a[i]^k);//set存入
	}
	for(int i=0;i<n;i++){
		if(s.count(a[i])){
			cout<<"Alice"<<endl;
			return;
		}
	}
	sort(a,a+n);
	n=unique(a,a+n)-a;//去重
	for(int i=0;i<n;i++){
		a[i]^=k;
		add(a[i]);
	}
	int cnt=0;
	for(int i=32;i>=0;i--){
		if(d[i]) cnt++;
	}
	if((1<<cnt)==n){
		cout<<"Bob"<<endl;
	}
	else cout<<"Draw"<<endl;
}
int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	T=1;
	cin>>T;
	while(T--)
	{
		solve();
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值