线性基

有一个整数集合 S=a1,a2,,anS=a_1,a_2,…,a_n,它的一个子集合 S=ak1,ak2,,akmS'=a_{k_1},a_{k_2},…,a_{k_m},如果它满足原集合的每个数 ai=ci,1ak1+ci,2ak2++ci,makma_i=c_{i,1}a_{k_1}+c_{i,2}a_{k_2}+…+c_{i,m}a_{k_m},其中 ci,jc_{i,j} 为整数,且 mm 最小,则称 SS'SS线性基

long long xxj[SIZE],tmp[SIZE];
bool flag;
void XXJ_insert(long long x){
    for(int i=SIZE;i>=0;i--)
        if(x&((long long)1<<i))
            if(!xxj[i]){
				xxj[i]=x;
				return;
			}
            else
				x^=xxj[i];
    flag=1;
}
bool XXJ_check(long long x){
    for(int i=SIZE;i>=0;i--)
        if(x&((long long)1<<i))
            if(!xxj[i])
				return 0;
            else
				x^=xxj[i];
    return 1;
}
long long XXJ_qmax(){
	long long res=0;
    for(int i=SIZE;i>=0;i--)
        res=max(res,res^xxj[i]);
    return res;
}
long long XXJ_qmin(){
    if(flag)
		return 0;
    for(int i=0;i<=SIZE;i++)
        if(xxj[i])
			return xxj[i];
}
long long XXJ_query(long long k){
    long long res=0;
	int cnt=0;
    k-=flag;
	if(!k)
		return 0;
    for(int i=0;i<=SIZE;i++){
        for(int j=i-1;j>=0;j--)
            if(xxj[i]&((long long)1<<j))
				xxj[i]^=xxj[j];
        if(xxj[i])
			tmp[cnt++]=xxj[i];
    }
    if(k>=((long long)1<<cnt))
		return -1;
    for(int i=0;i<cnt;i++)
        if(k&((long long)1<<i))
			res^=tmp[i];
    return res;
}

其中 SIZESIZE 是所有数中二进制下最大的位数。

操作

  • XXJ_insert(x)\text{XXJ\_insert}(x):插入数 xx

  • XXJ_check(x)\text{XXJ\_check}(x):检查 xx 能否得到。

  • XXJ_qmax()\text{XXJ\_qmax}():求目前能得到的最大值。

  • XXJ_qmin()\text{XXJ\_qmin}():求目前能得到的最小值。

  • XXJ_query(k)\text{XXJ\_query}(k):求能得到的第 kk 小值,若没有返回 1-1

时间复杂度都在 O(SIZE)O(SIZE) 左右。

posted @ 2021-08-22 01:54  luckydrawbox  阅读(8)  评论(0)    收藏  举报  来源