cf 959F Mahmoud and Ehab and yet another xor task(线性基)

Meaning of the question: For an array of length n, there are q questions: how many subsequences of the first l numbers are exclusive or x? The result is the remainder of 1e9+7

First introduce the linear base (from OI Wiki):

Linear basis is a set of basis in vector space, which can usually solve some problems related to XOR.

To put it more generally, another set is constructed from one set. It has the following properties:

  • The elements of the linear basis can XOR each other to get the value obtained by the XOR of all the elements of the original set.

  • The linear basis is the smallest set that satisfies property 1.

  • There is no subset of linear basis whose XOR sum is 0.

  • The XOR scheme of each element in the linear base is unique, that is, the number of XORs produced by different XOR combinations in the linear base is different.

  • The highest binary bit of each element in the linear basis is different from each other.

For linear basis array a[], a[i] represents the value of the highest 1 in the i-th place

The method of constructing a linear basis: Convert each number p in the original set to a two-level system, sweep from high to low, and for the i-th position is 1, if a[i]==0, let a[x]=p, End of scan;

If a[i]!=0, set p^=a[i] and continue scanning.

Code:


void insert(int p) {
    //具体从最高位多少开始扫描,视具体情况而定
    for(int i=30;i>=0;i--) {
        //若i>31,使用(1LL)<<i
        if(p&1<<i){
            if(!a[i]) {
                a[i]=p;
                break;
            }
            p^=a[i];
        }
    }

}

 Through the above insertion process, we can know whether a number can be XORed out. If it is inserted successfully, it is not possible, otherwise it can.

For this question, we perform an offline query, sort the query from small to large, and then insert the number into the linear base. The number successfully inserted is tot, and the number of array elements that have been traversed is cnt. If it can be XORed out, then the subsequence The number is 2^(cnt-tot)

code show as below:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=1e5+10;
ll bit[maxn],num[maxn];
ll ans[maxn],a[maxn];
struct node{
    int l,x,id;
    bool operator<(const node &a) const{
        if(l!=a.l) return l<a.l;
        return x<a.x;
    }
}b[maxn];
int tot,cnt,n,m;
void inse(int x) {
    for(int i=28;i>=0;i--) {
        if(x&1<<i) {
            if(!bit[i]) {
                bit[i]=x;
                tot++;
                break;
            }
            x^=bit[i];
        }
    }
}
bool check(int x) {
    for(int i=28;i>=0;i--) {
        if(x&1<<i) {
            if(!bit[i]) return 0;
            x^=bit[i];
        }
    }
    return 1;
}
signed main() {
    scanf("%d%d",&n,&m);
    num[0]=1;
    for(int i=1;i<=n;i++) num[i]=(num[i-1]<<1)%mod;
    for(int i=1;i<=n;i++) scanf("%lld",a+i);
    for(int i=1;i<=m;i++) {
        scanf("%d%d",&b[i].l,&b[i].x);
        b[i].id=i;
    }
    sort(b+1,b+1+m);
    for(int i=1;i<=m;i++) {
        while(cnt<b[i].l) inse(a[++cnt]);
        if(check(b[i].x)) ans[b[i].id]=num[cnt-tot];
    }
    for(int i=1;i<=m;i++) {
        printf("%lld\n",ans[i]);
    }
}

​​​​​​​   

Guess you like

Origin blog.csdn.net/qq_44132777/article/details/109524554