• LOJ3048 「十二省联考 2019」异或粽子


    问题描述

    小粽是一个喜欢吃粽子的好孩子。今天她在家里自己做起了粽子。

    小粽面前有 (n) 种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为 (1)(n)。第 (i) 种馅儿具有一个非负整数的属性值 (a_i)。每种馅儿的数量都足够多,即小粽不会因为缺少原料而做不出想要的粽子。小粽准备用这些馅儿来做出 (k) 个粽子。

    小粽的做法是:选两个整数数 (l,r),满足 (1le lle rle n),将编号在 ([l,r]) 范围内的所有馅儿混合做成一个粽子,所得的粽子的美味度为这些粽子的属性值的异或和。(异或就是我们常说的 (mathrm{xor}) 运算,即 C/C++ 中的 ^ 运算符或 Pascal 中的 xor 运算符)

    小粽想品尝不同口味的粽子,因此它不希望用同样的馅儿的集合做出一个以上的粽子。

    小粽希望她做出的所有粽子的美味度之和最大。请你帮她求出这个值吧!


    题解

    分类考虑,动态用堆维护前 (k) 大的

    显然,题目中涉及到求 (a_l operatorname{xor} a_{l+1} operatorname{xor} cdots operatorname{xor} a_r) 的操作,则一定需要前缀异或

    (S(i)=a_1 operatorname{xor} a_2 operatorname{xor} cdots operatorname{xor} a_i),题意则转化为求 (S(i) operatorname{xor} S(j)(i<j)) 的前 (k) 大值的和。

    这是一个倒三角求值,可以补为正方形,即 (S(i) operatorname{xor} S(j))(2k) 大值的和。

    建立一个堆,一开始把 (forall i in [1,n],S(i) operatorname{xor} S(j)(i eq j)) 的最大值放到堆里。

    每次取堆顶,假设为 (S(i))(k) 大值,则 pop 之后把 (S(i)) 的第 (k+1) 大值入堆。

    以上操作可以通过 ( exttt{0-1 Trie}) 完成。


    ( exttt{Code})

    #include<bits/stdc++.h>
    using namespace std;
    
    #define int long long
    
    const int maxn = 500000 + 7;
    
    int n, k;
    int a[maxn], s[maxn];
    int ans;
    
    int ch[10000000][2], tot, size[10000000];
    
    //priority_queue <node> q;
    
    struct node {
    	int val, rk, id;
    	bool operator < (const node a) const{
    		return val < a.val;
    	}
    };
    
    priority_queue <node> q;
    
    void Init(void) {
        scanf("%lld%lld", &n, &k); k <<= 1;
        for(int i = 1; i <= n; i++) {
    		scanf("%lld", &a[i]);
    		s[i] = s[i - 1] ^ a[i];
    	}
    }
    
    void insert(int x) {
    	int p = 0;
    	for(int i = 31; i >= 0; i--) {
    		int d = (x >> i) & 1;
    		size[p] ++;
    		if(!ch[p][d]) ch[p][d] = ++tot;
    		p = ch[p][d];
    	}
    	size[p]++;
    }
    
    int query(int x, int t) {
    	int p = 0, res = 0;
        for(int i = 31; i >= 0; i--) {
    		int d = (x >> i) & 1;
    		if(ch[p][d ^ 1] == 0) p = ch[p][d];
    		else if(t <= size[ch[p][d ^ 1]]) p = ch[p][d ^ 1], res += (1ll << i);
    		else t -= size[ch[p][d ^ 1]], p = ch[p][d];
    	}
        return res;
    }
    
    void Work(void) {
        for(int i = 0; i <= n; i++) {
    		insert(s[i]);
    	}
    	for(int i = 0; i <= n; i++) {
    		int rec = query(s[i], 1);
    		q.push((node){rec, 1, i});
    	}
    	while(k--) {
    		node r = q.top(); q.pop();
    		ans += r.val;
    		if(r.rk < n) q.push((node){query(s[r.id], r.rk + 1), r.rk + 1, r.id});
    
    	}
    	ans >>= 1;
    	printf("%lld
    ", ans);
    }
    
    signed main(void) {
    	Init();
    	Work();
    	return 0;
    }
    
  • 相关阅读:
    小菜鸟学 MQ(三)
    小菜鸟 学MQ(二)
    小菜鸟学 MQ(一)
    CXF 自定义拦截器
    WebService 入门程序(一)
    查找满足条件的颜色并替换
    jsfl 巧用获取jsfl绝对路径,导入配置文件,注意配置文件无法改变舞台宽高
    jsfl 发布保存关闭
    jsfl 改变舞台宽高
    AS3 在不规则区域内拖动
  • 原文地址:https://www.cnblogs.com/liubainian/p/13020511.html
Copyright © 2020-2023  润新知