zoukankan      html  css  js  c++  java
  • [十二省联考2019 ] 异或粽子

    题目大意

    传送门
    给定一个长为n的序列, 最大化选出k个不同区间异或和的和
    (n,k<=5*10^5)

    solution

    先讲套路: 看到这类跟位运算有关的题,先想想Trie树

    (S_i) 为[1...i]区间的异或和,则任意一个区间[l,r]异或和为 (S_{l-1}) xor (S_r)
    考虑每个节点 i 作为右端点时第一次选择可能的贡献:
    选出1个节点j (j<=i) 作为左端点: 最大化 (S_j xor S_i)
    然后需要在所有节点中找出贡献最大的节点
    那么下一次该点i可能的有贡献点对就必须是 选出j,满足 (S_j xor S_i) 为次大值
    以此类推...

    所以我们建一个大根堆,先把所有点作为右端点的最大贡献点对加入
    然后对每个节点为记录其使用过了几次
    每删除一个堆顶,记录贡献之后
    若该点已使用cnt次,就将以该点为右端点的第cnt大贡献点对加入

    code

    #include<bits/stdc++.h>
    using namespace std;
    #define re register
    #define ll long long
    #define get getchar()
    #define in inline
    #define int unsigned
    in int read()
    {
        int t=0; char ch=get;
        while(ch<'0' || ch>'9') ch=get;
        while(ch<='9' && ch>='0') t=t*10+ch-'0', ch=get;
        return t;
    }
    const int _=1e6+23;
    struct Trie{
        int siz,ch[2];
    }tr[_<<6];
    int rt[_<<2], tot, s[_], n, m,now[_];
    #define ls(k) tr[k].ch[c]
    #define rs(k) tr[k].ch[1^c]
    in void insert(int a,short x,int k1,int k2)
    {
        if(x<0) { tr[k2].siz=tr[k1].siz+1; return;}
        int c=a>>x&1;
        if(k1) rs(k2)=rs(k1);
        ls(k2)=++tot;
        insert(a,x-1,ls(k1),ls(k2));
        tr[k2].siz=tr[ls(k2)].siz+tr[rs(k2)].siz;
    }
    in int query(int a,short x,int k,int lim)
    {
        if(x<0){ return 0;}
        int c=a>>x&1;
        if(tr[rs(k)].siz>=lim) return query(a,x-1,rs(k),lim)|(1<<x);
        else return query(a,x-1,ls(k),lim-tr[rs(k)].siz);
    }
    #define mp make_pair
    signed main()
    {
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
    #endif
        n=read(), m=read();
        rt[0]=++tot;
        insert(0,31,0,rt[0]);
        for(re int i=1;i<=n;++i)
        {
            int x=read(); s[i]=s[i-1]^x;
            rt[i]=++tot;
            insert(s[i],31,rt[i-1],rt[i]);
        }
        ll ans=0; priority_queue<pair<int,int> >q; //第一维是贡献,第二维是区间右端点
        for(re int i=1;i<=n;++i) {q.push(mp(query(s[i],31,rt[i],1),i)); now[i]=1;}
        while(m--)
        {
            ans+=q.top().first; int u=q.top().second; q.pop();
            q.push(mp(query(s[u],31,rt[u],++now[u]),u));
        }
        cout<<ans<<endl;
        return 0;
    }
    
    
    嗯,就这样了...
  • 相关阅读:
    io系列之常用流一
    C++ 函数参数的默认值
    C++ 函数匹配和作用域声明
    c++ vector 迭代器 demo
    C++ 函数重载和匹配
    C++函数重载和const
    C++函数重载
    iOS开源项目
    Linux系统/网络 笔记
    IO五种模式
  • 原文地址:https://www.cnblogs.com/yzhx/p/14568362.html
Copyright © 2011-2022 走看看