CF1895D题解

· · 题解

题解里怎么都用 trie,让我来篇不用 trie 的题解!

我们先找一下规律,容易发现只要知道了第一个数,那么后面的数就全知道了,现在的问题就是让 0- n-1 中的数全部出现。

我们设构造的数组的第一个为 k。 那么:

以此类推,所以我们发现 $b$ 中的所有数都可以表示为一个数异或上 $b_1$ 的形式。 我们发现直接考虑不太好做,于是我们考虑拆位。 如果说 $0- n-1$ 这些数中第 $j$ 位上有 $sum$ 个 1 的话,我们就必须得让 $b$ 数组最终也有 $sum$ 个 1。所以我们统计一下 $a_1,a_1 \oplus a_2,a_1 \oplus a_2 \oplus a_3...$ 中第j位上有多少个 1,如果说有 1 的个数恰好等于 $sum$,那么第一个数这位上是要填 0 的,因为 $0 \oplus 1=1$,否则就必须填1。 至于为啥有解的话我也不太会证,本来想写个判断的,结果看到题目中没说无解输出什么,就直接输出了。 参考代码实现(写的有点丑): ```cpp #include <bits/stdc++.h> #define N 500005 #define M 13000005 #define mod 998244353 #define lowbit(x) (x&-x) #define ls(x) llll[x] #define rs(x) rrrr[x] #define ll long long //#define int long long using namespace std; int t,n; int a[N],qian[N],b[N]; signed main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n; for(int i=2;i<=n;++i){//让i从2开始方便一些 cin>>a[i]; qian[i]=qian[i-1]^a[i];//处理前缀异或 } for(int j=0;j<=21;++j){ if((1<<j)>=n)continue; int sum=0; for(int i=0;i<n;++i){ if((i>>j)&1)++sum; } //统计有应该有多少个1 int sum1=0,sum2=0; for(int i=2;i<=n;++i){ if((qian[i]>>j)&1)++sum1; else ++sum2; } if(sum1==sum){//如果说1的个数和要求的一样 ;//那么这位填0 } else b[1]+=(1<<j);//否则填1 } ll lst=b[1]; for(int i=1;i<=n;++i){ cout<<(lst^a[i])<<' ';//最后已知第一位直接求出每一位 lst^=a[i]; } return 0; } /* k a1^k a1^a2^k a1^a2^a3^k */