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

(>Codeforcesspace959 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
", ans[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/mangoyang/p/9301364.html