蒟蒻快活不了了,必须找点题摩擦了
记录表
| 省份 | d1t1 | d1t2 | d1t3 | d2t1 | d2t2 | d2t3 |
| 十二省联考 | $√$ | $√$ | ||||
| ZJOI | ||||||
| HNOI | ||||||
| GX/GZOI | ||||||
| BJOI | $√$ | |||||
| SNOI | ||||||
| JSOI | ||||||
| TJOI | ||||||
| SDOI |
注意事项:
1. GZOI 不是广州 OI,是贵州 OI!
2. 本文只贴签到题的完整题解,较长的题解放新文链接。
十二省联考
d1t1 异或粽子
签到题
这道题有很像的原题而且做法没什么区别
我这么菜甚至以前还出过这道题
好吧,总之就是这题很送
可持久化 trie,第 $i$ 个版本表示后缀 $[i,n]$ 中,第一大前缀异或和。用一个堆,开 $pair$ 存放 $[1...n,n]$ 这 $n$ 个后缀的最大前缀和 及每个最大前缀和对应的后缀的左端点,然后弹 $k-1$ 次堆顶,每次弹堆顶时 把堆顶那个最大前缀和对应的后缀求下一大前缀和,将其存入堆(若这个后缀中的所有前缀都被弹过,就忽略关于下一大前缀和的操作)。第 $k$ 次的堆顶就是答案了。
这样做的正确性显然:你正常的想法就是进行 $k-1$ 轮这样的操作:找到序列的最大异或和,删掉它。而任何时刻,序列的最大异或和都必定对应一个区间,也就对应一个左端点,那么我们只要同时维护所有左端点对应的后缀的答案,再取最优就行了。
时间复杂度 $O(k\times log(n))$。
我的 code(把以前自己写的标程拷过来改一改):
1 #pragma GCC optimize(2) 2 #include<bits/stdc++.h> 3 #define rep(i,x,y) for(int i=(x);i<=(y);++i) 4 //#define int long long 5 //#define uint long long 6 #define ll long long 7 #define N 500002 8 #define pii pair<uint,int> 9 #define mp make_pair 10 using namespace std; 11 inline uint read(){ 12 uint x=0; bool f=1; char c=getchar(); 13 for(;!isdigit(c);c=getchar()) if(c=='-') f=0; 14 for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0'); 15 if(f) return x; 16 return 0-x; 17 } 18 int n,k,num[N][34],rt[N],rk[N],cnt; 19 uint a,sum[N]; 20 struct Tree{int siz,son[2];}tr[N*34]; 21 void modify(int lst,int &o,int x,int step){ 22 if(!o) o=++cnt, tr[o]=tr[lst]; 23 tr[o].siz++; 24 if(!step) return; 25 if(!num[x][step]) tr[o].son[0]=0, modify(tr[lst].son[0], tr[o].son[0], x, step-1); 26 else tr[o].son[1]=0, modify(tr[lst].son[1], tr[o].son[1], x, step-1); 27 } 28 uint query(int o,int x,int k,uint v,int step){ 29 assert(o); 30 if(!step) return v; 31 int s=num[x][step]^1; 32 if(tr[tr[o].son[s]].siz>=k) return query(tr[o].son[s], x, k, v+(1ll<<(step-1)), step-1); 33 else return query(tr[o].son[s^1], x, k-tr[tr[o].son[s]].siz, v, step-1); 34 } 35 priority_queue<pii> pq; 36 ll ans; 37 signed main(){ 38 n=read(), k=read(); 39 modify(0,rt[0],0,32); 40 rep(i,1,n){ 41 a=read(), sum[i]=sum[i-1]^a; 42 a=sum[i]; 43 rep(j,1,32) num[i][j]=0; 44 int cnt=0; 45 while(a>0) num[i][++cnt]=a&1, a>>=1; 46 rk[i]=1, pq.push(mp(query(rt[i-1],i,1,0,32),i)); 47 modify(rt[i-1],rt[i],i,32); 48 } 49 pii cur; 50 for(int i=1;i<k;++i){ 51 cur=pq.top(), pq.pop(); 52 ans+=cur.first; 53 int x=cur.second; 54 if(rk[x]+1<=x) pq.push(mp(query(rt[x-1],x,++rk[x],0,32),x)); 55 } 56 cout<<ans+pq.top().first; 57 return 0; 58 } 59 /* 60 3 3 61 2 2 4 62 */