interlinkage:
https://www.luogu.org/problemnew/show/P5283
description:
solution:
- 显然有$O(n^2)$的做法,前缀和优化一下即可
- 正解做法是先确定一个右端点$r$,找到最优的$l$使得该区间的异或和最大,这个可以用可持久化$Trie$实现。不懂的话可以在我的博客里搜索
- 对每个点取出来后把答案放进一个堆里,显然当前的堆顶一定会对答案产生贡献
- 然后我们考虑每次取出的右端点,它依旧可能产生贡献。即上一次取的最优的$l$把原来的区间割裂成了两部分,把这两部分的最优解算出来再次放进堆里就好
- 这样取出$k$个就一定是最优的$k$个了
code:
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #include<cmath> #include<algorithm> using namespace std; typedef long long ll; const int N=5e5+15; int n,k,cnt; int rt[N]; ll a[N]; struct Trie { int ch[2]; int id,siz; }t[N*40]; inline ll read() { char ch=getchar();ll s=0,f=1; while (ch<‘0‘||ch>‘9‘) {if (ch==‘-‘) f=-1;ch=getchar();} while (ch>=‘0‘&&ch<=‘9‘) {s=(s<<3)+(s<<1)+ch-‘0‘;ch=getchar();} return s*f; } void ins(int &now,int pre,int bit,int id,ll val) { now=++cnt;t[now]=t[pre];t[now].siz++; if (bit==-1) { t[now].id=id; return; } if ((val>>bit)&1) ins(t[now].ch[1],t[pre].ch[1],bit-1,id,val); else ins(t[now].ch[0],t[pre].ch[0],bit-1,id,val); } int query(int k1,int k2,int bit,ll val) { if (bit==-1) return t[k2].id; int d=(val>>bit)&1; if (t[t[k2].ch[d^1]].siz-t[t[k1].ch[d^1]].siz>0) return query(t[k1].ch[d^1],t[k2].ch[d^1],bit-1,val); return query(t[k1].ch[d],t[k2].ch[d],bit-1,val); } struct node { int l,r,x,id;ll val; node(int _l=0,int _r=0,int _x=0) { l=_l;r=_r;x=_x; id=query(rt[l-1],rt[r],31,a[x]); val=a[x]^a[id-1]; } }; bool operator < (const node &a,const node &b) {return a.val<b.val;} priority_queue<node> Q; int main() { freopen("xor.in","r",stdin); freopen("xor.out","w",stdout); n=read();k=read(); for (int i=1;i<=n;i++) a[i]=a[i-1]^read(); for (int i=1;i<=n;i++) ins(rt[i],rt[i-1],31,i,a[i-1]); for (int i=1;i<=n;i++) Q.push(node(1,i,i)); ll ans=0; while (k--) { node u=Q.top();Q.pop(); ans+=u.val; if (u.l<u.id) Q.push(node(u.l,u.id-1,u.x)); if (u.r>u.id) Q.push(node(u.id+1,u.r,u.x)); } printf("%lld\n",ans); return 0; }
原文地址:https://www.cnblogs.com/xxzh/p/10677736.html
时间: 2024-10-09 16:53:28