题解:P11008 『STA - R7』异或生成序列
思路
对于异或,有一个小性质,即 \(x\;\oplus\;y\;\oplus\;x=y\)。
题目中我们也能运用这个性质,考虑到对于相邻的两个 \(b_{i}\),它们的表达式中有一个共同的 \(p_{i}\),所以异或两个相邻的 \(b_{i}\) 就会把那个出现了两次的 \(p_{i}\) 消除,即:
但是这样有什么意义呢?意义很重大啊!因为我们知道 \(b_{i}\;\oplus\;b_{i+1}\) 的值,所以可以有意义的将式子移项:
同时显然的 \(p_{i+1}=p_{i}\;\oplus\;b_{i}\)。
这个式子告诉我们,只要有 \(p_{i}\) 的值,就可以求出 \(p_{i+1}\) 以及以后的 \(p_{i}\),那么我们只要枚举 \(p_{1}\) 就行。
考虑暴力判断 \(p_{1}\) 生成的序列的可行性,这样是 \(O(n^2)\) 的,考虑优化。
我们知道,实际上判就只是判这三个因素:
1.序列的所有元素大于 \(0\)。
2.序列的所有元素小于 \(n+1\)。
3.序列没有重复的元素。
三条件实际对于所有有解输入都成立,因为每个 \(p_{i}(i>1)\) 的表达式形如:
如果有解,那么 \((b_{1}\;\oplus\;...\;\oplus\;b_{i-1})\) 一定对于任何的 \(i>1\) 都不重复,不然对于任何一个解,都会出现重复的情况。所以 \((b_{1}\;\oplus\;...\;\oplus\;b_{i-1})\) 互不重复,异或任意 \(p_{1}\) 自然也不重复。
考虑条件一二,因为所有元素大于一个数等价于最小元素大于那个数,所有元素小于一个数等价于最大元素小于那个数,所以考虑快速求出上式最大最小值的方法。
由于上式为位运算,是在每位进行的,如果想要贪心的最大或最小,就需要依次决定每位,从高位到低位。
所以考虑记录 \(b\) 每一个的前缀异或和,然后求最大最小值时,贪心的从高往低考虑取 \(0\) 还是 \(1\) 即可。具体的,这个做法我们用 trie 树实现。
解法
维护 trie 树的解法。
首先考虑维护一颗由 \(b\) 前缀构成的树,然后每次可以枚举 \(p_{1}\),运用 trie 树判断运用 \(p_{1}\) 生成的 \(p\) 序列是否合法,即最大值是否小于 \(n+1\),最小值是否大于 \(0\),如果合法,按思路构造即可。最后通过队列一层一层清空即可,这样只会清空不为 \(0\) 的节点。
Code
#include <bits/stdc++.h>
using namespace std;
const int N=42'000'000;
int son[N][2],idx;
void gun() {
queue<int> q;
q.push(0);
while(q.size()) {
auto t=q.front();
q.pop();
for(int i=0;i<2;i++) if(son[t][i]) q.push(son[t][i]),son[t][i]=0;
}
}
void insert(int x) {
int p=0;
for(int i=19;i>=0;i--) {
int u=(x>>i)&1;
if(!son[p][u]) son[p][u]=++idx;
p=son[p][u];
}
}
int qry_max(int x) {
int p=0,ans=0;
for(int i=19;i>=0;i--) {
int u=(x>>i)&1;
if(son[p][!u]) {
ans+=(1<<i);
p=son[p][!u];
}
else p=son[p][u];
}
return ans;
}
int qry_min(int x) {
int p=0,ans=0;
for(int i=19;i>=0;i--) {
int u=(x>>i)&1;
if(son[p][u]) p=son[p][u];
else {
ans+=(1<<i);
p=son[p][!u];
}
}
return ans;
}
int n;
int a[N];
signed main() {
int tt;
cin>>tt;
while(tt--) {
cin>>n;idx=0;
for(int i=1;i<n;i++) cin>>a[i];int cnt=0;
for(int i=1;i<n;i++) {cnt^=a[i],insert(cnt);}
for(int i=1;i<=n;i++)
if(qry_max(i)<=n&&qry_min(i)>=1) {
cnt=0;
cout<<i<<' ';
for(int j=1;j<n;j++) {
cnt^=a[j];
cout<<(cnt^i)<<' ';
}
break;
}
gun();
puts("");
}
return 0;
}

浙公网安备 33010602011771号