题目
题目背景
′
′
I
f
e
e
l
s
i
c
k
.
′
′
''\rm I\;feel\;sick.''
′′Ifeelsick.′′
题目描述
给一个
n
×
m
n\times m
n×m 的
01
01
01 矩阵,问有多少个子矩阵在模
2
2
2 意义下的秩为
k
k
k 。
数据范围与提示
n
,
m
,
k
≤
500
n,m,k\le 500
n,m,k≤500,时间限制
5
s
5\rm s
5s 。
对 “秩” 的解释:从线性代数的角度说,它是线性无关的向量数量。从 O I OI OI 的角度说,把每一行看成一个 2 2 2 进制数,“秩” 就是其线性基的元素个数。
思路
肯定是部分枚举。考虑先枚举左边界,再从上到下枚举下边界。
我们在一维线性基问题中,常常有这样一种贪心策略:尽量使用编号大的值。不难发现,这样的结果 等价于直接从反方向插入元素。那么,由于我们已枚举了下边界,最暴力的做法就是再枚举一个上边界,然后依次加入每一行对应的二进制数。利用这一招就可以把这一步操作优化掉。
不妨以左边为高位、右边为低位。我们求一个数组 x i x_i xi 表示第 i i i 行代表的二进制数在线性基中对应的位置。即,在线性基的一顿操作下,它最终变成了一个最高位对应第 x i x_i xi 列的二进制数。由线性基的过程,可以知道,如果右边界不包含 x i x_i xi,那么这个数字就会插入失败。换句话说,能够插入成功当且仅当右边界包含 x i x_i xi 。
把所有第 i i i 行、第 x i x_i xi 列的点标记出来,问题转化为,矩形内必须恰好有 k k k 个点。容斥一下,转化为 ≤ k \le k ≤k,然后 t w o p o i n t e r s \rm two\;pointers twopointers 同时移动上边界和右边界即可。因为 x i x_i xi 的范围足够下,可以桶排(计数排序)求出右端点移动带来的点的数量改变。
计算一下复杂度。对于一个左端点,做了
n
n
n 行的线性基,如果用
b
i
t
s
e
t
\tt bitset
bitset 优化,就是
O
(
n
4
w
)
\mathcal O({n^4\over w})
O(wn4) 的。而
t
w
o
p
o
i
n
t
e
r
s
\rm two\;pointers
twopointers 只有
O
(
n
3
)
\mathcal O(n^3)
O(n3) 的复杂度。估计也蛮卡常的?