• 【算法】线性基求异或和第k大


    题目链接

    如果说,线性基中异或的最大数(的二进制形式)是一串 连续的,没有带后续0 的1,那相信聪明的你一定会求第k大,因为第k大其实就是k。

    现在相当于告诉你在这一串1中夹了很多0,问你第k大是多少。那么你其实可以不用管中间的0,把k的二进制形式弄出来,然后把中间省略0给插回去就好了。
    解释一下就相当于把线性基异或后出来的最大值里的所有1都给挤到最后,然后求出第k大,再把你弄走的0给丢回去。

    eg:异或后最大值为101100110,问第20大

    挤到后面去后成11111,第k大是10100,把0插回去成为100100000,第20大便是100100000

    显然的证明:随便弄出两个数,把他们转成2进制,然后去掉非公共的0,发现两个数的相对大小关系不变。两个数的大小比较相当于在他们位数相同(或添上前导0后位数相同)的情况下比他们的字典序,而除去公共0后字典序的相对关系是不变的。

    嗯就是这样,记得特判可不可以异或出0。

    #include <bits/stdc++.h>
    using namespace std;
    int n,m,tot = 0;
    long long a[1000005];
    long long k[61],tt,x,cnt;
    bool flag = 1;
    void insert(long long x){
        for (int i=60;i>=0;i--){
            if (x&((long long)1LL<<i)) {
                if (k[i]) x=x^k[i];
                else {
    				tot++;
                    k[i]=x;
                    return ;
                }
            }
        }
    }
    long long ask(long long x) {
    	if (tot < n && x == 1) return 0;
    	if (tot < n) x--;
    	if (x >= (1LL << (long long)cnt)) return -1;
    	long long ans = 0;
    	for (int i = 0;i <= 60;i++) {
    		if (k[i]) {
    			if (x % 2) ans ^= (long long)k[i];
    			x /= 2;
    		}
    	}
    	return ans;
    }
    int main(){
     	cin>>n;
    	for (int i=1;i<=n;i++) {
    	    cin>>a[i];
    		insert(a[i]);
    	}
    	scanf("%d",&m);
    	for (int i = 0;i <= 60;i++) {
    		for (int j = 1;j <= i;j++) {
    			if (k[i] & ((long long)1LL << (long long)(j - 1))) k[i] ^= (long long)k[j - 1];
    		}
    		if (k[i]) cnt++;
    	}
    	for (int i = 1;i <= m;i++) {
    		long long x;
    		scanf("%lld",&x);
    		printf("%lld
    ",ask(x));
    	}
        return 0;
    }
    
  • 相关阅读:
    Redhat6 —— Yum详解
    jQuery——bind绑定多事件用法
    织梦之路——织梦自由列表页分页链接绝对路径化(SEO)
    PHP算法——等宽等像素值截取字符串
    PHP算法——文件大小排序(KB、MB、GB、TB)
    HDU 3647 Tetris
    HDU 2442 Bricks
    ZOJ 2112 Dynamic Rankings
    HDU 3001 Travelling
    HDU 3559 Frost Chain
  • 原文地址:https://www.cnblogs.com/Illusions/p/13985907.html
Copyright © 2020-2023  润新知