Luogu 4869 albus就是要第一个出场

BZOJ 2844

被NOIP模拟赛题弄自闭了QuQ。

因为本题要求异或,所以自然地构造出线性基,假设本题中给出的数有$n$个,而我们构造出的线性基大小为$m$,那么每一个可以异或出来的数相当于出现了$2^{n - m}$次。

可以把那些已经存在于异或空间中的数看成$0$,因为我们一共能凭凑出$2^m$个不同的异或值,剩下的$n - m$个数相当于可选可不选,所以每一个值有$2^{n - m}$种方案异或上一个$0$。

然后算一算$q$在不重复的异或空间中排第几就可以了,具体做法就是把$q$用二进制表示,如果有一位$1$在线性基中存在,那么就说明剩下的数可选可不选,一共有$2^($线性基中的排名$)$个数比它小,最后还要计算$0$,需要$+1$。

假设排名为$k$,答案就是$k*2^{n - m}$。

时间复杂度$O(nlogn)$。

Code:

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;

const int N = 1e5 + 5;
const int M = 35;
const ll P = 10086LL;

int n, q, a[N];

inline void read(int &X) {
    X = 0; char ch = 0; int op = 1;
    for(; ch > '9' || ch < '0'; ch = getchar())
        if(ch == '-') op = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}

namespace Lb {
    int m = 0, p[M];
    
    inline void ins(int v) {
        for(int i = 30; i >= 0; i--)
            if((v >> i) & 1) {
                if(!p[i]) {
                    ++m;
                    p[i] = v;
                    break;
                }
                v ^= p[i];
            }
    }
    
} using namespace Lb;

inline ll fpow(ll x, ll y) {
    ll res = 1LL;
    for(; y > 0; y >>= 1) {
        if(y & 1) res = res * x % P;
        x = x * x % P;
    }
    return res;
}

int main() {
//    freopen("4.in", "r", stdin);
    
    read(n);
    for(int i = 1; i <= n; i++) {
        read(a[i]);
        ins(a[i]);
    }
    read(q);
    
    int stk[M], top = 0;
    for(int i = 0; i <= 30; i++)
        if(p[i]) stk[top++] = i;
    ll ans = 0LL;
    for(int i = 0; i < top; i++)
        if((q >> stk[i]) & 1)
            ans += 1LL << i;
        
    ans %= P;
    printf("%lld
", (ans * fpow(2, n - top) % P + 1) % P);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/CzxingcHen/p/9883581.html