线性基
线性基可以“存储”一个数的集合的所有子集的异或和。它支持查询最大/最小/第k小子集异或和或一个异或和是否存在。线性基可以插入,但不能删除。
long long a[55], s[55], top;
void insert(long long x) {
for(int i = 62; i >= 0; i--) if(x&(1ll<<i)) {
if(!a[i]) {
a[i] = x;
return;
}
x ^= a[i];
}
}
int exist(long long x) {
for(int i = 62; i >= 0; i--) if(x&(1ll<<i)) {
x ^= a[i];
if(!x) return 1;
}
return 0;
}
long long query_max() {
long long ans = 0;
for(int i = 62; i >= 0; i--) if((ans^a[i]) > ans) ans ^= a[i];
return ans;
}
long long query_min() {
for(int i = 0; i <= 62; i++) if(a[i]) return a[i];
return -1;
}
long long kth(int k) {
for(int i = 62; i >= 0; i--) for(int j = i-1; j >= 0; j--) if(a[i]&(1ll<<j)) a[i] ^= a[j];
top = 0;
for(int i = 0; i <= 62; i++) if(a[i]) s[top++] = a[i];
long long ans = 0;
for(int i = 62; i >= 0; i--) if(k&(1ll<<i)) ans ^= a[i];
return ans;
}
矩阵
高斯消元
几乎就是手动消元的过程。
void gauss() {
for(int i = 0; i < n; i++) {
int r = i;
for(int j = i+1; j < n; j++) if(fabs(a[j][i]) > fabs(a[r][i])) r = j;
for(int j = 0; j <= n; j++) swap(a[i][j], a[r][j]);
for(int j = n; j >= i; j--) for(int k = i+1; k < n; k++) a[k][j] -= a[k][i]/a[i][i] * a[i][j]; // 提高精度
}
for(int i = n-1; i >= 0; i--) { // 回代
for(int j = i+1; j < n; j++) a[i][n] -= a[j][n] * a[i][j];
a[i][n] /= a[i][i];
}
}
矩阵的逆
用高斯消元。
中国剩余定理
中国剩余定理用于求解形如
x≡bi(modmi)
x
≡
b
i
(
mod
m
i
)
的一组方程。
设有
n
n
个方程,我们计算另外“特殊的”个方程组的解。第
p
p
个“特殊方程组”形如;
x≡bi(modmi),i≠p
x
≡
b
i
(
mod
m
i
)
,
i
≠
p
。
可以轻易地用扩展欧几里得求出这些“特殊方程组”的解。
则原方程组的解,就等于每一组“特殊方程组”的解乘以其序号对应的系数的和,对
∏ni=1mi
∏
i
=
1
n
m
i
取模。
int china() {
int M = 1, ans = 0;
for(int i = 0; i < n; i++) M *= m[i];
for(int i = 0; i < n; i++) {
int d, y;
exgcd(m[i], M/m[i], d, d, y);
ans = (ans + y*(M/m[i])*a[i]) % M;
}
return ans;
}
Upd on 2018.7.20:
设
M=∏ni=1mi,Mi=Mmi
M
=
∏
i
=
1
n
m
i
,
M
i
=
M
m
i
则
x=∑ni=1aiinv(Mi,mi)Mi(modM)
x
=
∑
i
=
1
n
a
i
i
n
v
(
M
i
,
m
i
)
M
i
(
mod
M
)
大步小步算法
大步小步算法用于解方程
ax≡b(modn)
a
x
≡
b
(
mod
n
)
,时间复杂度为
O(n−−√)
O
(
n
)
。
根据欧拉定理,如果有解,则解一定在
[0,n)
[
0
,
n
)
中。
BSGS的基本思想是先求出
ei=aimodn(i<n−−√)
e
i
=
a
i
mod
n
(
i
<
n
)
,全部存在哈希表中。对于之后的
i
i
,只需检查是否有即可。
这体现了一种分组的思想。
Miller-Rabin素数测试
Miller-Rabin算法是基于费马小定理的。
这个Miller_Rabin没有用二次探测定理,但不保证会出错。
int miller_rabin(int x) {
if(x == 2) return 1;
for(int i = 0; i < 10; i++) {
int a = rand() % (x-2) + 2;
if(qpow(a, x, x) != a) return 0;
}
return 1;
}
Pollard Rho
明天