概述
[AGC045] A - Xor Battle
知识点 线性基
参考博客:
Menci 线性基学习笔记
fffasttime 异或和与线性基问题入门
总体看下来感觉知识点不算难,但是得多看不同的博客才能找到自己看懂这个知识点的节奏…
过于严谨的数学定义不予深究,毕竟也只是在网络博客的只言碎语中学习到了该知识点,并未进行严谨的系统学习。简单的说,如果给出某个序列,我们可以据此得到这个序列所蕴含的基底,通过这组基底,可以张成一个至少包含该序列中所有值的空间。因而,如果我们需要对原序列的进行某些异或操作,就有可能可以等价地通过其线性基来操作。
构造办法如下:
const int L = 63;
ll d[L];
bool add(ll x){
for(int i = L - 1; i >= 0; i--) if(x & 1ll << i){
if(d[i] == -1){d[i] = x; return true;}
x ^= d[i];
}
return false;
}
如何获得基底的思想与Gauss消元类似,在矩阵中不断相减得到最简三角矩阵。
在这道题中,我们设置集合 S [ i ] S[i] S[i],包含了第i次操作前能够使得最终结果为0的所有元素。从后往前遍历,有如下关系:
- 若 s [ i ] = 0 s[i] = 0 s[i]=0,那么 S [ i ] = S [ i + 1 ] ∪ { x ∣ x = a [ i ] ⊕ u , u ∈ S [ i + 1 ] } S[i] = S[i + 1] ∪{x|x = a[i] ⊕ u, u ∈S[i + 1]} S[i]=S[i+1]∪{x∣x=a[i]⊕u,u∈S[i+1]}
- 若 s [ i ] = 1 s[i] = 1 s[i]=1:若 a [ i ] ∈ S [ i + 1 ] a[i]∈S[i + 1] a[i]∈S[i+1]:记 x ∈ S [ i ] x∈S[i] x∈S[i] ,那么必有 x ⊕ a [ i ] ∈ S [ i + 1 ] x ⊕ a[i] ∈S[i + 1] x⊕a[i]∈S[i+1],只有这样才能保证无论1号怎么选择最终都会失败,从而由集合 S S S的封闭性易知 S [ i ] = S [ i + 1 ] S[i] = S[i+ 1] S[i]=S[i+1];当 a [ i ] ∉ S [ i + 1 ] a[i]∉S[i + 1] a[i]∈/S[i+1]时,进行i操作之前的结果 x x x与 x ⊕ a [ i ] x⊕a[i] x⊕a[i]总有一个不在 S [ i + 1 ] S[i + 1] S[i+1]中,此时1必胜。
因为集合的封闭性,所以张成的向量空间里所有的值都可以被取到。综上考虑,我们可以用线性基维护该集合。(然而这一块感觉还是有点不太清楚qwq
const int maxn = 200 + 10;
ll a[maxn];
const int L = 63;
ll d[L];
bool add(ll x){
for(int i = L - 1; i >= 0; i--) if(x & 1ll << i){
if(d[i] == -1){d[i] = x; return true;}
x ^= d[i];
}
return false;
}
int main(){
// Fast;
int t; scanf("%d", &t); while(t--){
memset(d, -1, sizeof d);
int n; scanf("%d", &n);
for(int i = 0; i < n; i++) scanf("%lld", a + i);
char s[maxn]; scanf("%s", s);
int flag = 0;
for(int i = n - 1; i >= 0; i--){
if(add(a[i]) && s[i] == '1'){
flag = 1;
break;
}
}
printf("%dn", flag);
}
return 0;
}
最后
以上就是可爱宝贝为你收集整理的[AGC045] A - Xor Battle的全部内容,希望文章能够帮你解决[AGC045] A - Xor Battle所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复