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

    链接:

    题目

    题目大意:

    求一段数列前 (k) 大区间异或和的和。

    正文:

    本题和 【Luogu P2048】[NOI2010] 超级钢琴 思路极其相似。对于前 (k) 大,我们可以用堆来维护。

    不同于超级钢琴的是,本题是异或和,不能直接根据前缀和大小排序,那怎么办呢?考虑用 0/1Trie 解决。从高位到低位插入数字,顺便记录子树大小,至于查询,毕竟是第 (k) 大,我们可以像平衡树一样通过子树大小确定当前一位。

    代码:

    const int N = 2e7 + 10;
    
    int n, k;
    ll sum[N];
    
    struct Trie
    {
    	int ch[N][2];
    	ll siz[N], tot;
    	void ins(ll val) 
    	{
    		int u = 0;
    		for (int i = 31; ~i; --i)
    		{
    			bool k = (val >> i) & 1; siz[u]++;
    			if (!ch[u][k]) ch[u][k] = ++tot;
    			u = ch[u][k];
    		}
    		siz[u] ++;
    		return;
    	}
    	
    	ll query(ll val, int n) 
    	{
    		int u = 0;ll ans = 0;
    		for (int i = 31; ~i; --i)
    		{
    			bool k = (val >> i) & 1;
    			if(!ch[u][k ^ 1]) u = ch[u][k];
    			else if (n <= siz[ch[u][k ^ 1]]) u = ch[u][k ^ 1], ans |= 1ll << i;
    			else n -= siz[ch[u][k ^ 1]], u = ch[u][k];
    		}
    		return ans;
    	}
    }t;
    struct node
    {
    	ll x, rk, val;
    	inline bool operator < (const node& a) const
    	{
    		return val < a.val;
    	}
    };
    priority_queue<node> q;
    ll ans = 1;
    
    int main()
    {
    //	freopen(".in", "r", stdin);
    //	freopen(".out", "w", stdout);
    	scanf ("%d%d", &n, &k);
    	t.ins(0);
    	for (int i = 1; i <= n; i++)
    		scanf ("%lld", &sum[i]), sum[i] ^= sum[i - 1], t.ins(sum[i]);
    	for (int i = 0; i <= n; i++)
    		q.push((node){i, 1, t.query(sum[i], 1)});
    	for (int i = 1; i <= 2 * k; i++)
    	{
    		node x = q.top(); ans += x.val; q.pop();
    		if (x.rk < n) q.push((node){x.x, x.rk + 1, t.query(sum[x.x], x.rk + 1)});
    	}
    	printf ("%lld
    ", ans / 2);
    	return 0;
    }
    
  • 相关阅读:
    ssh
    datetime
    网络-sdn(2)
    django-drf
    Vscode前段常用插件
    Vscode离线安装插件
    CSS 实现绘制各种三角形
    flex布局
    js实现全选和取消全选
    购物车用Ajax向后台传参
  • 原文地址:https://www.cnblogs.com/GJY-JURUO/p/14349982.html
Copyright © 2011-2022 走看看