• 【线性基】Petrozavodsk Winter Training Camp 2018 Day 1: Jagiellonian U Contest, Tuesday, January 30, 2018 Problem A. XOR


    题意:给你一些数,问你是否能够将它们划分成两个集合,使得这两个集合的异或和之差的绝对值最小。

    设所有数的异或和为S,集合A的异或和为A。

    首先,S的0的位对答案不造成影响。

    S的最高位1,所对应的A的那一位一定可以为1,不妨设它为1。

    然后考虑后面的S的1位,尽量使A对应的位置为0,这样才能使S xor A,即B的值最大化,最接近A。

    用线性基来进行判定,看能否将最高位到目前这位(假定目前这位是0)的这个区间用给定的数线性表出,如果能,就将这位设成0,否则,就将这位设成1。

    妈的,其实整个过程只需要取出最大的线性基,然后尽量用较小的线性基去消掉除了最高位以外的1即可,得到的就是A!

    队友的代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define FOR(i,a,b) for (LL i=(a);i<=(b);++i)
    #define ROF(i,b,a) for (LL i=(b);i>=(a);--i)
    typedef long long LL;
    LL read(){
    	LL x=0,f=1; char ch=getchar();
    	while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
    	while (ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); }
    	return x*f;
    }
    
    const LL MAXN=300005;
    LL n,m,q,a[MAXN],b[MAXN],c[MAXN],f[100];
    int main() {
    	LL T=read();
    	while (T--) {
    		n=read(); m=0;
    		FOR(i,1,n) m^=a[i]=read();
    		FOR(i,1,n) a[i]&=m;
    		memset(f,0,sizeof(f));
    		FOR(i,1,n) {
    			ROF(j,62,0)
    			if ((a[i]>>j)&1) {
    				if (!f[j]) { f[j]=a[i]; break; }
    				else {
    					//if (a[i]<f[j]) swap(a[i],f[j]);
    					a[i]^=f[j];
    				}
    			}
    		}
    		LL x=-1,y=0;
    		ROF(i,62,0) if (f[i]) { x=i; break; }
    		if (x>=0) y=f[x];
    		//cerr<<y<<' '<<m<<endl;
    		ROF(i,x-1,0)
    		if (f[i])
    			if ((y>>i)&1) y^=f[i];
    		cout<<abs(y-(y^m))<<endl;
    	}
    	return 0;
    }
    
    /*
    2
    4
    1 2 3 4
    5
    3 7 3 9 5
    
    */
  • 相关阅读:
    C#事件理解
    二叉排序树查找算法代码
    二叉排序树查找算法代码
    深度学习——02、深度学习入门——卷积神经网络
    深度学习——02、深度学习入门——卷积神经网络
    程序员表白代码
    程序员表白代码
    程序员表白代码
    vbs实现消息轰炸
    vbs实现消息轰炸
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/8849270.html
Copyright © 2020-2023  润新知