标签:trie树 运算符 com 好孩子 lld 正整数 data 现在 持久
Description
题目描述
小粽是一个喜欢吃粽子的好孩子。今天她在家里自己做起了粽子。
小粽面前有 nn 种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为 11 到 nn。第 ii 种馅儿具有一个非负整数的属性值 a_iai?。每种馅儿的数量都足够多,即小粽不会因为缺少原料而做不出想要的粽子。小粽准备用这些馅儿来做出 kk 个粽子。
小粽的做法是:选两个整数数 ll, rr,满足 1 \leqslant l \leqslant r \leqslant n1?l?r?n,将编号在 [l, r][l,r] 范围内的所有馅儿混合做成一个粽子,所得的粽子的美味度为这些粽子的属性值的异或和。(异或就是我们常说的 xor 运算,即 C/C++ 中的 ˆ
运算符或 Pascal 中的 xor
运算符)
小粽想品尝不同口味的粽子,因此它不希望用同样的馅儿的集合做出一个以上的 粽子。
小粽希望她做出的所有粽子的美味度之和最大。请你帮她求出这个值吧!
输入格式
第一行两个正整数 nn, kk,表示馅儿的数量,以及小粽打算做出的粽子的数量。
接下来一行为 nn 个非负整数,第 ii 个数为 a_iai?,表示第 ii 个粽子的属性值。 对于所有的输入数据都满足:1 \leqslant n \leqslant 5 \times 10^51?n?5×105, 1 \leqslant k \leqslant \min\left\{\frac{n(n-1)}{2},2 \times 10^{5}\right\}1?k?min{2n(n−1)?,2×105}, 0 \leqslant a_i \leqslant 4 294 967 2950?ai??4294967295。
输出格式
输出一行一个整数,表示小粽可以做出的粽子的美味度之和的最大值。
Solution
想来一年前去体验省选时我还是个暴力都没拿到分的蒟蒻。。。
现在已经可以独立做出来啦 开心!
年年岁岁题相似,岁岁年年人不同
正文:
设a[ i ]:1~i 的异或和
对于每个 i ,建立一颗trie树储存 1~i 的 a;
在这棵trie树上搜索与a[i]异或所得值最大的一个数,并边找边删去它,把这个所得值和i加入大根堆中
1~n扫完后开始在堆中找最大的k个数,每弹出一个堆顶要再在它的trie树里找到并删去最大值,再加入堆中
可是这样数组太大,于是用可持久化优化,记得加数和删树时都要重建树,不然会对共用节点的其他树造成影响
Code
#include <cstdio> #include <cstdlib> #include <queue> #define ll long long using namespace std; const int N=1e6+10; struct node { int ch[2],sum; }f[N*80]; int n,k,rt[N],tot,cnt[N]; ll a[N],ans,an=1; void build(int x,int y,int t,ll pos) { if(t<0) return ; int wh=(pos>>t)&1; f[x].ch[!wh]=f[y].ch[!wh]; f[x].ch[wh]=++tot; f[f[x].ch[wh]].sum=f[f[y].ch[wh]].sum+1; build(f[x].ch[wh],f[y].ch[wh],t-1,pos); } struct mode { int id; ll v; bool operator <(const mode &o)const { return v<o.v; } }; priority_queue <mode> q; ll get(int x,int y,int t,ll pos) { if(t<0) return 0; int wh=(pos>>t)&1; int yy=f[y].ch[!wh],zz=f[y].ch[wh]; if(f[yy].sum>0) { f[x].ch[wh]=zz; f[x].ch[!wh]=++tot; f[tot].sum=f[yy].sum-1; return (an<<t)+get(f[x].ch[!wh],yy,t-1,pos); } else { f[x].ch[!wh]=yy; f[x].ch[wh]=++tot; f[tot].sum=f[zz].sum-1; return get(f[x].ch[wh],zz,t-1,pos); } } int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); a[i]^=a[i-1]; rt[i]=++tot; build(rt[i],rt[i-1],32,a[i-1]); } for(int i=1;i<=n;i++) { cnt[i]++; int nw=++tot; ll xx=get(nw,rt[i],32,a[i]); rt[i]=nw; q.push((mode){i,xx}); } while(k--) { mode tp=q.top(); q.pop(); ans+=tp.v; if(++cnt[tp.id]<=tp.id) { int nw=++tot; ll xx=get(nw,rt[tp.id],32,a[tp.id]); rt[tp.id]=nw; q.push((mode){tp.id,xx}); } } printf("%lld\n",ans); return 0; }
标签:trie树 运算符 com 好孩子 lld 正整数 data 现在 持久
原文地址:https://www.cnblogs.com/hsez-cyx/p/12283811.html