题解:P11651 [COCI 2024/2025 #4] Xor

· · 题解

我们按位计算答案。

设当前枚举到了第 k 位,下文计 b_i 表示 a_i 在第 k 位的值,c_i 表示 a_ik-1 位的值(当 k=1c_i=0)。

我们讲这三个贡献分开算,前两个是容易的,做第三个时,考虑讲 $c_i$ 排序,然后用双指针维护。排序的复杂度为 $O(\log n)$,再加上枚举 $k$ 的复杂度,总复杂度为 $O(n\log n \log maxa)$,可以拿到五十二分。 瓶颈在于排序,我们考虑用类似于基数排序的方法来实现这个排序,在从小到大枚举 $k$ 时,若 $c_i=1$,就将 $i$ 放到序列的后面,若 $c_i=0$,就将 $i$ 放到序列的前面,相等的 $c$ 之间的相对位置不改变,这样总复杂度就由 $O(n\log n \log maxa)$ 降为 $O(n\log maxa)$ 了。 代码: ```cpp #include<bits/stdc++.h> #define rep(i, j, k) for(int i=(j); i<=(k); ++i) #define per(i, j, k) for(int i=(j); i>=(k); --i) #define print(a, len) cout<<#a<<"= "; rep(i, 0, len-1) cout<<(a)[i]<<' '; cout<<endl; using namespace std; namespace DEBUG{ template<class T> void _debug(const char *s, T x){cout<<s<<'='<<x<<endl;} template<class T, class... Nxt> void _debug(const char *s, T x, Nxt... nxt){ while(*s!=',') cout<<*s++; cout<<'='<<x<<','; _debug(s+1, nxt...); } template<class T> ostream& operator<<(ostream& c, vector<T> x){ c<<'['; for(auto v:x) c<<v<<", "; return c<<']'; } #ifdef ck #define debug(...) 0 #else #define debug(...) _debug(#__VA_ARGS__, __VA_ARGS__) #endif } using namespace DEBUG; const int N=5e5+7; int n, a[N], b[N], c[N], d[N], c1, c2, ans; int buc[N]; inline bool bit(int s, int i){return s>>i&1;} inline int mod(int s, int k){return s&((1<<k)-1);} signed main(){ cin.tie(0)->sync_with_stdio(0); cin>>n; rep(i, 1, n) cin>>a[i]; rep(k, 0, 30){ auto bit=[&](int i){return a[i]>>k&1;}; auto mod=[&](int i){return a[i]&((1<<k)-1);}; bool res=0; if(n+1&1) rep(i, 1, n) res^=bit(i); if(k){ c1=c2=0; rep(i, 1, n) if(mod(i)<1<<k-1) b[++c1]=i; else c[++c2]=i; rep(i, 1, c1) d[i]=a[b[i]]; rep(i, 1, c2) d[c1+i]=a[c[i]]; rep(i, 1, n) a[i]=d[i]; int pos=n+1; rep(i, 1, n){ while(pos>i && mod(i)+mod(pos-1)>=1<<k) --pos; pos=max(pos, i); if(n-pos+1&1) res^=1; } } if(res) ans^=1<<k; } cout<<ans; } ```