蒟蒻快活不了了,必须找点题摩擦了

记录表

省份 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 */
View Code

相关文章: