[BZOJ2844]albus就是要第一個出場(線性基)
阿新 • • 發佈:2018-12-08
Address
Solution
- 本題只不過是考查對線性基的理解
- 先介紹下一個
顯然的結論 - 如果 個數構成的異或線性基有 個數,並且通過異或運算能使得數 被表出
- 那麼這 個數有 個子集的異或和為
- 感性的理解: 個數在構建線性基的過程中,有 個數沒有被扔進線性基
- 這樣這 個數可以等效地看作為線性基內的 個數以及 個
- 於是這個結論就比較顯然了(每個 都可以任意選或不選)
- 回到原問題
- 發現我們要求的就是有多少個子集的異或和不超過 ,最後加上 即為答案
- 考慮按位統計,把 拆成不超過 個 形式的數之和
- 轉化成不超過 個形如下面的問題
- 有多少個子集的異或和在 範圍內
- 也就是有多少個子集的異或和去掉最低 個二進位制位之後為
- 將每個數除以 後構建線性基即可計算出
- 複雜度
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
inline int read()
{
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 1e5 + 5, M = 40, ZZQ = 10086;
int n, a[N], q, bas[M], m, ans = 1;
int qpow(int a, int b)
{
int res = 1;
while (b)
{
if (b & 1) res = 1ll * res * a % ZZQ;
a = 1ll * a * a % ZZQ;
b >>= 1;
}
return res;
}
void ins(int x)
{
int i;
Rof (i, 30, 0)
{
if (!((x >> i) & 1)) continue;
if (bas[i] == -1) return (void) (bas[i] = x);
else x ^= bas[i];
}
m++;
}
bool canbe(int x)
{
int i, res = 0;
Rof (i, 30, 0)
{
if (bas[i] == -1) continue;
if (((res >> i) & 1) ^ ((x >> i) & 1)) res ^= bas[i];
}
return res == x;
}
int query(int offset, int val)
{
int i;
m = 0;
memset(bas, -1, sizeof(bas));
For (i, 1, n) ins(a[i] >> offset);
if (canbe(val)) return qpow(2, m);
return 0;
}
int main()
{
int i;
n = read();
For (i, 1, n) a[i] = read();
q = read();
if (!q) return (void) puts("1"), 0;
q--;
Rof (i, 30, 0)
if ((q >> i) & 1)
ans = (ans + query(i, (q >> i) ^ 1)) % ZZQ;
memset(bas, -1, sizeof(bas)); m = 0;
For (i, 1, n) ins(a[i]);
if (canbe(q)) ans = (ans + qpow(2, m)) % ZZQ;
std::cout << ans << std::endl;
return 0;
}