zoukankan      html  css  js  c++  java
  • HDU3949 XOR

    嘟嘟嘟


    集训的时候发现自己不会线性基,就打算学一下。
    这东西学了挺长时间,其实不是因为难,而是天天上午考试,下午讲题,结果晚上就开始颓了。
    今天总算是有大块的时间好好学了一遍。
    这里推荐menci大佬的博客:线性基学习笔记


    这道题就是求一个集合的第(k)小亦或和。


    首先线性基的概念、构造方法什么的看上面的blog就好啦。
    这里补充一点,只有求第(k)小(大)的亦或和的时候才用把每一位独立开来,即必须满足(p[i] = 2 ^i)。其他的操作(比如亦或最大值)就不用了。


    那么现在我们已经得到了线性基,且满足如果(p[i])存在,就有(p[i] = 2 ^ i)
    首先,对于不存在的(p[i]),要把他踢出去,因为这一位在计算答案的时候是没有贡献的。
    然后如果求第(k)小,就把(p[i])从低位到高位存到另一个数组中(去0位);如果是第(k)大,就应该从高位到低位存下来。
    那么对于(k),转换成二进制,如果第(i)位为(0),就把答案亦或上(p[i])
    大体的流程就是这样。
    接下来说一下细节:
    1.如果线性基大小小于(n),就说明有的数能被其他数亦或得到,也就是说,答案是包含(0)的。这时候就要把(k)减1。
    2.无解条件是(k > 2^cnt - 1)。之所以减1,是因为虽然有(2 ^ cnt)种可能,但是0是不算的,因此只有(2 ^cnt - 1)个数。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxN = 63;
    inline ll read()
    {
    	ll ans = 0;
    	char ch = getchar(), last = ' ';
    	while(!isdigit(ch)) {last = ch; ch = getchar();}
    	while(isdigit(ch)) {ans = (ans << 1) + (ans << 3) + ch - '0'; ch = getchar();}
    	if(last == '-') ans = -ans;
    	return ans;
    }
    inline void write(ll x)
    {
    	if(x < 0) x = -x, putchar('-');
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + '0');
    }
    
    int n, m;
    ll p[maxN + 5];
    In void insert(ll x)
    {
    	for(int i = maxN; i >= 0; --i)
    	{
    		if((x >> (ll)i) & 1) 
    		{
    			if(p[i]) x ^= p[i];
    			else
    			{
    				for(int j = i - 1; j >= 0; --j) if((x >> j) & 1) x ^= p[j];
    				for(int j = maxN; j > i; --j) if((p[j] >> i) & 1) p[j] ^= x;
    				p[i] = x; return;
    			}
    		}
    	}
    }
    ll b[maxN + 5], cnt = 0;
    In void change()		//第k小,正着存 
    {
    	for(int i = 0; i <= maxN; ++i) if(p[i]) b[cnt++] = p[i];
    }
    In ll query(ll k)
    {
    	if(cnt < n) --k;
    	if(k > (1LL << cnt) - 1) return -1;
    	ll ret = 0;
    	for(int i = 0; i < cnt; ++i) 
    	{
    		if((k >> i) & 1) ret ^= b[i];
    	}
    	return ret;
    }
    In void init()
    {
    	Mem(p, 0); Mem(b, 0); cnt = 0;
    }
    
    int main()
    {
    	int T = read(), cntT = 0;;
    	while(T--)
    	{
    		printf("Case #%d:
    ", ++cntT);
    		init();
    		n = read(); ll x;
    		for(int i = 1; i <= n; ++i) x = read(), insert(x);
    		change();
    		m = read();
    		for(int i = 1; i <= m; ++i) x = read(), write(query(x)), enter;
    	}
    	return 0;
    }
    
  • 相关阅读:
    ElementUI Form 表单
    ElementUI 快速入门
    您即将提交的信息不安全
    pandas excel合并去重
    openpyxl刷新透视表
    安装kube-prometheus
    多个py文件生成一个可运行exe文件
    Locust关联和参数化
    使用Docker运行locust
    Python locust阶段压测
  • 原文地址:https://www.cnblogs.com/mrclr/p/10253559.html
Copyright © 2011-2022 走看看