• BZOJ3689 异或之


    题面

    题目描述

    给定n个非负整数A[1], A[2], ……, A[n]。
    对于每对(i, j)满足1 <= i < j <= n,得到一个新的数A[i] xor A[j],这样共有n*(n-1)/2个新的数。求这些数(不包含A[i])中前k小的数。
    注:xor对应于pascal中的“xor”,C++中的“^”。

    输入

    第一行2个正整数 n,k,如题所述。
    以下n行,每行一个非负整数表示A[i]。

    输出

    共一行k个数,表示前k小的数。

    样例输入

    4 5
    1
    1
    3
    4
    

    样例输出

    0 2 2 5 5
    

    【样例解释】

    1 xor 1 = 0 (A[1] xor A[2])
    1 xor 3 = 2 (A[1] xor A[3])
    1 xor 4 = 5 (A[1] xor A[4])
    1 xor 3 = 2 (A[2] xor A[3])
    1 xor 4 = 5 (A[2] xor A[4])
    3 xor 4 = 7 (A[3] xor A[4])
    前5小的数:0 2 2 5 5

    【数据范围】

    对于100%的数据,2 <= n <= 100000; 1 <= k <= min{250000, n*(n-1)/2};
    0 <= A[i] < 2^31

    题解

    堆 + trie.
    首先明确, trie树上可以找到一个数的xor第k大(小).
    我们把每个数的异或第(2)小先装进堆里面(异或第(1)小是自己异或自己, 不在题目考虑范围内), 每次取出堆头, 假设堆头是第(p)小, 则插入第(p + 1)小即可.
    注意应该取(2k)次, 因为每两次得到的结果是相同的.

    #include <cstdio>
    #include <cctype>
    #include <queue>
    
    namespace Zeonfai
    {
    	inline int getInt()
    	{
    		int a = 0, sgn = 1;
    		char c;
    		while(! isdigit(c = getchar()))
    			if(c == '-')
    				sgn *= -1;
    		while(isdigit(c))
    			a = a * 10 + c -'0', c = getchar();
    		return a * sgn;
    	}
    
    	inline void print(int a)
    	{
    		if(! a)
    			return;
    		print(a / 10);
    		putchar(a % 10 + '0');
    	}
    
    	inline void println(int a)
    	{
    		if(a < 0)
    			putchar('-'), a *= -1;
    		if(a == 0)
    			putchar('0');
    		print(a);
    		putchar(' ');
    	}
    }
    
    const int N = 100000;
    
    struct trieTree
    {
    	struct node
    	{
    		node *suc[2];
    		int cnt;
    
    		inline node()
    		{
    			suc[0] = suc[1] = NULL;
    			cnt = 0;
    		}
    	};
    
    	node *rt;
    
    	inline trieTree()
    	{
    		rt = new node;
    	}
    
    	inline void insert(int w)
    	{
    		node *u = rt;
    		for(int i = 30; ~ i; -- i)
    		{
    			int k = w >> i & 1;
    			if(u->suc[k] == NULL)
    				u->suc[k] = new node;
    			++ (u = u->suc[k])->cnt;
    		}
    	}
    
    	inline int query(int w, int k)
    	{
    		node *u = rt;
    		int res = 0;
    		for(int i = 30; ~ i; -- i)
    		{
    			int tmp = w >> i & 1;
    			if(u->suc[tmp] != NULL && u->suc[tmp]->cnt >= k)
    				u = u->suc[tmp];
    			else
    				k -= u->suc[tmp] == NULL ? 0 : u->suc[tmp]->cnt, u = u->suc[tmp ^ 1], res += 1 << i;
    		}
    		return res;
    	}
    }trie;
    
    struct record
    {
    	int id, k, w;
    
    	inline record(int _id, int _k ,int _w)
    	{
    		id = _id, k = _k, w = _w;
    	}
    
    	inline int friend operator <(record a, record b)
    	{
    		return a.w > b.w;
    	}
    };
    
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("BZOJ3689.in", "r", stdin);
    	#endif
    	using namespace Zeonfai;
    	int n = getInt(), k = getInt();
    	static int a[N];
    	for(int i = 0; i < n; ++ i)
    		trie.insert(a[i] = getInt());
    	static std::priority_queue<record> hp;
    	for(int i = 0; i < n; ++ i)
    		hp.push(record(i, 2, trie.query(a[i], 2)));
    	for(int i = 0; i < k << 1; ++ i)
    	{
    		record res = hp.top();
    		hp.pop();
    		if(i & 1)
    			println(res.w);
    		if(res.k < n)
    			hp.push(record(res.id, res.k + 1, trie.query(a[res.id], res.k + 1)));
    	}
    }
    
  • 相关阅读:
    Android 之 Intent(意图)
    初识 Android
    SSM + VUE 实现简单的 CRUD
    VueUI -- iView4.0简单使用
    axios解决跨域问题(vue-cli3.0)
    Mybatis 逆向工程
    获取input type=file 的文件内容(纯文本)
    vue常见问题处理 -- 页面刷新时,如何保持原有vuex中的state信息
    mysql安装、使用 -- windows
    vue关于mock的简单使用
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/7115232.html
Copyright © 2020-2023  润新知