洛谷P4869 albus就是要第一个出场

洛谷 P4869 albus就是要第一个出场

Description

已知一个长度为$n$的正整数序列$A$(下标从$1$开始),令$S = { x|x \le x \le n }$,$S$的幂级$2^S$定义为$S$所有子集构成的集合。定义映射$f:2^S \rightarrow Z$,$f( \emptyset ) = 0$,$f(T) = XOR { A _ t },(t \in T)$

现在$albus$把$2^S$中每个集合的$f$值计算出来, 从小到大排成一行, 记为序列$B$(下标从$1$开始)。

给定一个数, 那么这个数在序列$B$中第$1$次出现时的下标是多少呢?

Solution

令长度为$n$正整数序列$A$的线性基为$B$,非线性基中元素构成集合为$C$

定义集合$F = { f(T) | T \subseteq 2^S }$

有结论

  • 对于任意元素$a \in F$,$a$的出现次数均为$2 ^ {n - |B|}$

  • 证明:

    首先$a$可以由$B$中若干元素唯一表出,设这些元素构成的集合为$D$

    考虑集合$C$任意子集$E$,我们想在$B$中找到一个子集使其与$E$的异或和恰好为$a$

    • 若$D$与$E$有交集,那么我们先将$D$中的相交元素直接替换为$E$中的相同元素,这样一来$D$与$E$就没有交集了
    • $D$与$E$没有交集,我们一定可以在$B$中另找一个子集$G$使得$XOR { E } = XOR { G }$,那么$XOR { E } \ xor\ XOR { G } \ xor\ XOR{ D } = XOR {D } = a$

证毕

知道了这一结论后,我们通过数$x$的排名便可知道它第一次出现的次数

时间复杂度为$\mathcal {O} (n \log n)$,瓶颈在线性基的插入

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <cstdio>
#include <cstring>
#include <algorithm>

const int Mod = 10086;
struct Linear_Base {
static const int N = 31;
int n, Size, p[N + 2];
inline void Insert(int x) {
for (int i = N; i >= 0; --i)
if ((x >> i) & 1) {
if (p[i] == 0) {
p[i] = x, ++Size;
break;
}
x ^= p[i];
}
}
} S;

int main() {
int n, q;
scanf("%d", &n);
for (int i = 1, x; i <= n; ++i) {
scanf("%d", &x);
S.Insert(x);
}
scanf("%d", &q);
int Rank = 0, Cnt = 1;
for (int i = 0, tmp = 1; i <= 30; ++i)
if (S.p[i] != 0) {
if ((q >> i) & 1) (Rank += tmp) %= Mod;
tmp <<= 1;
}
for (int i = 1; i <= n - S.Size; ++i) Cnt = 2 * Cnt % Mod;
printf("%d\n", (1LL * Cnt * Rank + 1) % Mod);
return 0;
}