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; }