zoukankan      html  css  js  c++  java
  • 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)));
    	}
    }
    
  • 相关阅读:
    你的MongoDB Redis设置用户名密码了吗?看看shodan这款邪恶的搜索引擎吧!~
    聊聊数据库(MySql)连接吧,你真的清楚吗?
    .net Mongo Driver 1.0与2.0的对比与2.0的优化
    浅谈 JavaScript new 执行过程及function原理
    Jquery源码分析与简单模拟实现
    使用HttpWebRequest模拟登陆阿里巴巴(alibaba、httpwebrequest、login)
    Url以.(点)结尾,在使用httpwebrequest读取的时候,微软会有一个bug……
    VS超强调试技巧--忍不住想赞一下
    ClickOnce部署疑难杂症:更新时部署与应用程序标识不一致问题。要安装此应用程序,请修改此文件的清单版本或卸载之前存在的应用程序。
    MAC地址的介绍(单播、广播、组播、数据收发)
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/7115231.html
Copyright © 2011-2022 走看看