Codeforces 959 F. Mahmoud and Ehab and yet another xor task

\(>Codeforces\space959 F. Mahmoud\ and\ Ehab\ and\ yet\ another\ xor\ task<\)

题目大意 : 给出一个长度为 \(n\) 序列 \(A\),和 \(q\) 次询问,对于每一次询问给出两个数 \(l, x\) ,你需要计算在前缀和 \(A[1, l]\) 中选取若干个数,使得它们 \(xor\) 起来的结果等于 \(x\) 的方案数

$n , q \leq 10^5 \ 0 \leq A_i \leq 2^{20} $

解题思路 :

首先考虑离线,发现将询问按照 \(l\) 排序之后,询问每一个 \(l\) 时都可以构造出关于前缀$ A[1,l] $的线性基

考虑如果要在前缀 \(A[1,l]\) 中选取若干个数表示出 \(x\), 那么线性基中的元素必然能表示出 \(x\)

与此同时,如果线性基能表示出 \(x\)

那么对于每一个在前缀 \(A[1, l]\) 但不在线性基中元素 \(A_i\) 线性基都能表示出 \((x\ xor\ A_i)\)

所以线性基外的元素都可以选或者不选,那么方案数就是 \(2^{l -size}\) 其中 \(size\) 指的是线性基的大小

那么只需要对于询问离线,边向线性基内插入数边回答询问,判断是否能被线性基表示并算出线性基的大小即可

判断数是否能被线性基表示 : 对于数每一个有 \(1\) 的二进制位,\(xor\) 上线性基的对应位,判断是否变成了 \(0\)

求线性基的大小 : 加入元素的时候通过判断是否加入成功来维护


/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define P 1000000007
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
    int f = 0, ch = 0; x = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
    if(f) x = -x;
}
int a[200005], ans[200005], Bit[25], n, m, tot;
struct Query{ int l, x, id; } q[200005];
inline bool cmp(Query A, Query B){ return A.l < B.l; } 
inline ll Pow(ll a, ll b){
    ll ans = 1;
    for(; b; b >>= 1, a = a * a % P)
        if(b & 1) ans = ans * a % P;
    return ans;
}
inline void ins(int x){
    for(int i = 19; ~i; i--) if((1 << i) & x){
        if(!Bit[i]){ Bit[i] = x; return; }
        x ^= Bit[i];
    }    
}
inline void Answer(Query now){
    int x = now.x, lim = now.l, id = now.id, cnt = 0;
    for(int i = 19; ~i; i--) if(Bit[i]){
        cnt++;
        if((1 << i) & x) x ^= Bit[i];
    }
    if(x) ans[id] = 0; else ans[id] = Pow(2, lim - cnt);
}
int main(){
    read(n), read(m);
    for(int i = 1; i <= n; i++) read(a[i]);
    for(int i = 1; i <= m; i++){
        int l, x;
        read(l), read(x), q[i] = (Query){l, x, i};
    }
    int p = 1;
    sort(q + 1, q + m + 1, cmp);
    for(; !q[p].l && p <= m; p++)
        if(!q[p].x) ans[q[p].id] = 1; else ans[q[p].id] = 0;
    for(int i = 1; i <= n; i++){
        ins(a[i]); 
        while(q[p].l == i && p <= m) Answer(q[p++]);
    }
    for(int i = 1; i <= m; i++) printf("%d\n", ans[i]);
    return 0;
}
posted @ 2018-07-12 19:03  Joyemang33  阅读(273)  评论(0编辑  收藏  举报