zoukankan      html  css  js  c++  java
  • [十二省联考2019] 异或粽子 解题报告 (可持久化Trie+堆)

    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
    ",ans);
        return 0;
    }
  • 相关阅读:
    SVN库迁移整理方法----官方推荐方式
    SVN跨版本库迁移目录并保留提交日志
    微信公众号 发送图文消息
    Egret白鹭开发微信小游戏排行榜功能
    双滑动列表实现
    unity之资深工程师
    unity之高级工程师
    lua踩坑系列之浅拷贝与深拷贝
    lua之table.remove你不知道的坑
    unity之Layout Group居中显示
  • 原文地址:https://www.cnblogs.com/xxzh/p/10677736.html
Copyright © 2011-2022 走看看