令$f_{i}$(一个集合)表示当第$i$步开始时第0方必胜当且仅当$xin f_{i}$,初始$f_{n+1}={0}$
当$p_{i}=0$时,$f_{i}={x|xin f_{i+1}或(xoplus a_{i})in f_{i+1}}$;当$p_{i}=1$,$f_{i}={x|xin f_{i+1}且(xoplus a_{i})in f_{i+1}}$
归纳$f_{i}$具有以下性质:若$x,yin f_{i}$,则$(xoplus y)in f_{i}$,如果只有$p_{i}=0$显然满足此性质,考虑当$p_{i}=1$时,对$a_{i}$是否存在于$f_{i+1}$中分类讨论:
1.若$a_{i}in f_{i+1}$,根据此性质,则有$f_{i}=f_{i+1}$
2.若$a_{i} otin f_{i+1}$,同样根据此性质,若$(xoplus a_{i})in f_{i+1}$,则$a_{i}in f_{i+1}$,与假设矛盾,因此$f_{i}=emptyset$
这个性质类似于线性基,因此用线性基来维护$f_{i}$即可,时间复杂度为$o(tnlog_{2}a_{i})$

1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 205 4 #define ll long long 5 int t,n,ans; 6 ll a[N],w[N]; 7 char s[N]; 8 void add(ll k){ 9 for(int i=59;i>=0;i--) 10 if (k&(1LL<<i)){ 11 if (!w[i])w[i]=k; 12 k^=w[i]; 13 } 14 } 15 bool check(ll k){ 16 for(int i=59;i>=0;i--) 17 if (k&(1LL<<i)){ 18 if (!w[i])return 0; 19 k^=w[i]; 20 } 21 return 1; 22 } 23 int main(){ 24 scanf("%d",&t); 25 while (t--){ 26 scanf("%d",&n); 27 for(int i=1;i<=n;i++)scanf("%lld",&a[i]); 28 scanf("%s",s+1); 29 memset(w,0,sizeof(w)); 30 ans=0; 31 for(int i=n;i;i--) 32 if (s[i]=='0')add(a[i]); 33 else{ 34 if (!check(a[i])){ 35 ans=1; 36 break; 37 } 38 } 39 printf("%d ",ans); 40 } 41 }