zoukankan      html  css  js  c++  java
  • 【简】题解 P5283 [十二省联考2019]异或粽子

    传送门:P5283 [十二省联考2019]异或粽子

    题目大意:

    给一个长度为n的数列,找到异或和为前k大的区间,并求出这些区间的异或和的代数和。

    QWQ:

    考试时想到了前缀异或 想到了对每个数按二进制拆分 最高位取一定比前面所有取优

    但是呆住了 没有想到是对前缀异或拆分

    对于位运算等操作可以考虑 线性基和trie

    因为 ai xor aj=aj xor ai 所以吧这种情况算进去就取ans/2

    因为 i​=j 时异或为0是最小的 不会影响答案

    把各个前缀异或插进数组

    询问强制以每个点为前面的一个端点 查询第x大的值

    先把所有的第1大的插进堆里

    每次取堆中最大 统计答案

    当前取出的最大是强制的区间第x大 把区间第x+1大插入队里

    代码:

    #include<bits/stdc++.h> 
    using namespace std;
    #define ll long long
    #define C getchar()-48
    inline ll read()
    {
        ll s=0,r=1;
        char c=C;
        for(;c<0||c>9;c=C) if(c==-3) r=-1;
        for(;c>=0&&c<=9;c=C) s=(s<<3)+(s<<1)+c;
        return s*r;
    } 
    #define R register
    const ll N=20000000+10;
    ll n,k,ans;
    ll a[N],sum[N],sz[N];
    ll tr[N][2],top;
    struct xin{
        ll w,cs,v;
        friend bool operator < (xin a,xin b)
        {
            return a.v<b.v;
        }
    };
    priority_queue<xin>q;
    inline void into(ll v)
    {
        int u=0;
        for(int i=31;i>=0;i--)
        {
            ll tmp=(v>>i)&1;sz[u]++;
            if(!tr[u][tmp]) tr[u][tmp]=++top;
            u=tr[u][tmp];
        }
        sz[u]++;
    }
    inline ll ask(ll v,int cs)
    {
        ll u=0,ans=0;
        for(int i=31;i>=0;i--)
        {
            ll tmp=(v>>i)&1;
            if(!tr[u][tmp^1]){u=tr[u][tmp];continue;}
            if(cs<=sz[tr[u][tmp^1]]){u=tr[u][tmp^1];ans|=1LL<<i;continue;}
            if(cs>sz[tr[u][tmp^1]]){cs-=sz[tr[u][tmp^1]];u=tr[u][tmp];continue;}
        }
        return ans;
    }
    int main()
    {
        freopen("xor.in","r",stdin);
        freopen("xor.out","w",stdout); 
        n=read();k=read();k<<=1;
        for(R int i=1;i<=n;i++) a[i]=read();
        for(R int i=1;i<=n;i++) sum[i]=sum[i-1]^a[i];
        for(int i=0;i<=n;i++) into(sum[i]);
        for(int i=0;i<=n;i++) q.push((xin){i,1,ask(sum[i],1)});
        for(int i=1;i<=k;i++)
        {
            xin tmp=q.top();q.pop();ans+=tmp.v;
            if(tmp.cs<n) q.push((xin){tmp.w,tmp.cs+1,ask(sum[tmp.w],tmp.cs+1)});
        }
        cout<<(ans>>1)<<endl;
        return 0;
    }
  • 相关阅读:
    制作在线简历(一)——Loading与底部菜单
    然而这并没有什么卵用
    移动开发中Fiddler的那些事儿
    多种方法实现Loading(加载)动画效果
    总结)Nginx/LVS/HAProxy负载均衡软件的优缺点详解
    SQLServer和MySQL job和 event定时器的差别
    全局ID的重要性
    Windows操作系统上各种服务使用的端口号, 以及它们使用的协议的列表
    Linux发展历史图
    奇特的Local System权限(转载)
  • 原文地址:https://www.cnblogs.com/1436177712qqcom/p/11191800.html
Copyright © 2011-2022 走看看