首页 > 其他 > 详细

LG5283 异或粽子

时间:2019-05-03 13:05:13      阅读:131      评论:0      收藏:0      [点我收藏+]

题意

共有\(n\)个数,选择\(k\)个不同的\([l,r]\)区间,使得它们的异或和最大
$ 1 \leq n \leq 5 \times 10^5,k \leq 2 \times 10^5$

思路

先会想到前缀异或和,这样求\([l,r]\)区间异或和只需要用\(pre[l-1]\oplus pre[r]\)以此减少运算次数。然后由于是异或,又会想到\(trie\),然后想一想,好像要用可持久化!!!完了太菜了不会。
但为了偷懒,必须思考。思考过后发现,不用可持久化,\([l,r]\)区间算\([l,r],[r,l]\)两次,答案再除二就好了

#include <bits/stdc++.h>
using std::priority_queue;
const int N=500005;
long long trie[N<<5][2],a[N],x,ans;
int tot=1,n,k,size[N<<5];
struct note{
    int x,rk;
    long long w;
    bool operator < (const note &a)const{return w<a.w;}
};
priority_queue <note> q;
long long read(){
    long long t=0;
    char c=getchar();
    while (c<'0' || c>'9') 
    c=getchar();
    while (c>='0' && c<='9') t=t*10+c-'0',c=getchar();
    return t;
}

void add(long long x){
    int u=1;
    for (int i=31;i>=0;i--){
        int t=(x>>i)&1;
        size[u]++;
        if (!trie[u][t]) trie[u][t]=++tot;
        u=trie[u][t];
    }
    size[u]++;
}
long long query(long long x,int k){
    long long ans=0;
    int u=1;
    for (int i=31;i>=0;i--){
        int t=(x>>i)&1;
        if (trie[u][t^1] && size[trie[u][t^1]]>=k) 
        u=trie[u][t^1],ans^=1LL<<i;
        else k-=size[trie[u][t^1]],u=trie[u][t];
    }
    return ans;
}
int main(){
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++){
        x=read();
        a[i]=a[i-1]^x;
        add(a[i]);
    }
    add(0);
    for (int i=0;i<=n;i++) q.push(note{i,1,query(a[i],1)});
    for (int i=1;i<=k*2;i++){
        note t=q.top();q.pop();
        ans+=t.w;
        if (t.rk<=n) q.push(note{t.x,t.rk+1,query(a[t.x],t.rk+1)});
    }
    printf("%lld",ans/2);
} 

上海省选浪的太开心了,太菜了第二天\(99\)难受

LG5283 异或粽子

原文:https://www.cnblogs.com/flyfeather6/p/10804744.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!