P5283 [十二省联考 2019] 异或粽子
P5283 [十二省联考 2019] 异或粽子
[十二省联考 2019] 异或粽子
题目描述
小粽是一个喜欢吃粽子的好孩子。今天她在家里自己做起了粽子。
小粽面前有
小粽的做法是:选两个整数数 ˆ
运算符或 Pascal 中的 xor
运算符)
小粽想品尝不同口味的粽子,因此它不希望用同样的馅儿的集合做出一个以上的
粽子。
小粽希望她做出的所有粽子的美味度之和最大。请你帮她求出这个值吧!
输入格式
第一行两个正整数
接下来一行为
对于所有的输入数据都满足:
输出格式
输出一行一个整数,表示小粽可以做出的粽子的美味度之和的最大值。
----------------------------------------------------------------------------------
我们用依旧用 0/1Trie 维护粽子馅的xor前缀和
由题目可知:
小粽面前有n种互不相同的粽子馅儿
它不希望用同样的馅儿的集合做出一个以上的粽子
也就是说,我们只需要保证同样的 [l,r] 不会重复出现就好了
不难想到开一个优先队列来维护,每次在 [l,r] 内
用 [pos,r] 做出一个粽子之后,将其拆分为 [l,pos-1] 和 [pos+1,r] 就好了
Code:
#include<bits/stdc++.h> const int N=5e5+5; typedef long long ll; using namespace std; int n,k,tot; ll a[N]; int rt[N]; ll ans; struct Trie{ int ch[2],cnt,id; }t[N*40]; void ins(int &now,int last,int len,int id,int x) { now=++tot; t[now]=t[last]; t[now].cnt++; if(len==-1) { t[now].id=id; return ; } int bit=(x>>len)&1; ins(t[now].ch[bit],t[last].ch[bit],len-1,id,x); } int find_id(int l,int r,int len,int x) { if(len==-1)return t[r].id; int bit=(x>>len)&1; if(t[t[l].ch[bit^1]].cnt<t[t[r].ch[bit^1]].cnt) { return find_id(t[l].ch[bit^1],t[r].ch[bit^1],len-1,x); } else { return find_id(t[l].ch[bit],t[r].ch[bit],len-1,x); } } struct Range { int l,r,x,id; ll val; Range(int _l=0,int _r=0,int _x=0) { l=_l,r=_r,x=_x; id=find_id(rt[l-1],rt[r],31,a[x]); val=a[x]^a[id-1]; //cout<<"id:"<<l<<" "<<r<<" "<<x<<"=="<<id<<":"<<val<<"\n"; } bool operator <(const Range &r1)const{ return val<r1.val; } }; priority_queue<Range> Q; void work() { cin>>n>>k; for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); a[i]^=a[i-1]; } for(int i=1;i<=n;i++) { rt[i]=rt[i-1]; ins(rt[i],rt[i],31,i,a[i-1]); } for(int i=1;i<=n;i++) { Q.push(Range(1,i,i)); } for(int i=1;i<=k;i++) { Range tp=Q.top();Q.pop(); int l=tp.l,r=tp.r,id=tp.id,x=tp.x; ll val=tp.val; ans+=val; //cout<<"ans:"<<val<<"--"<<l<<" "<<id<<" "<<r<<"\n"; if(l<=id-1) Q.push(Range(l,id-1,x)); if(id+1<=r) Q.push(Range(id+1,r,x)); } printf("%lld",ans); } int main() { freopen("P5283.in","r",stdin);//freopen("P5283.out","w",stdout); work(); }