码蹄杯初赛第一场
5.
给定矩阵a∈Nm×m, b∈Nn×n (m,n∈N∗, m≥n),求
(i=0∑m−nj=0∑m−nk=0∑n−1l=0∑n−1(ai+k,j+l⊕bk.l))mod(109+7).
保证m,n≤103, (∀i) (∀j) (ai,j,bi,j≤109)。
按位异或对加法不满足分配律,所以直接化简这个和式是不可能的。考虑按位处理。用x(p)表示x从低到高的第p位。
考虑贡献法,ai,j与哪些元素进行了异或?于是原和式可以化为
i=0∑m−1j=0∑m−1k=max{i−(m−n),0}∑min{i,n−1}l=max{j−(m−n),0}∑min{j,n−1}(ai,j⊕bk,l).
记
kmin=max{i−(m−n),0}, kmax=min{i,n−1},lmin=max{j−(m−n),0}, lmax=min{j,n−1},
按位考虑,则原和式等于
b=0∑B−1i=0∑m−1j=0∑m−1k=kmin∑kmaxl=lmin∑lmax(ai,j(p)⊕bi,j(p))⋅2p,
其中B=⌈log(109)⌉。
对于取定的i,j,p,由异或的定义可知,我们只需数出b在区域N2∩([kmin,kmax]×[lmin,lmax])中0或1的数量即可。当ai,j(p)=0时数1,当ai,j=1时数0。这个计数值可以通过Θ(n2)预处理二维前缀和来Θ(1)求出。
7.
给定a∈(N∗)3×n (n∈N∗),求
(a0,⌊i/n2⌋⋅a1,⌊i/n⌋modn⋅a2,imodn)i=0n3−1
中最小的m∈N∗项。保证n≤105, m≤min{n3,2n}, (∀i∈{0,1,2}) (∀i) (∀j) (ai,j≤105)。
我真傻,真的。
可以先用a0,a1组合一遍乘积,用最小的m个再去与a2组合一遍。这一点我没想到。
用堆维护最小的m项是很容易想到的。
但这样还不够!暴力组合两个数组,复杂度仍然高达Θ(n2logm),我们需要找到更高效的寻找最小m个乘积的方式。很容易想到将它们先排序,然后怎么办?
如果我们将这两个数组组合的过程列成表格(以a0,a1分别作纵轴和横轴,表格中填上乘积),那末每一行、每一列都必定是递增的。现在我们的任务变为一个经典问题(多路归并问题):如何在这n行(从列的视角看当然也可以,这是等价的)已经有序的数列中选出最小的m个?很显然只需对各行维护一个从左往右移动的指针,指向下一个待选元素;每次选取所有待选元素中最小的那一个,并移动指针即可;而“选取所有待选元素中最小的那一个”正适合用一个小根堆来维护。进一步地,由于我们/只需求出最小的m个元素,我们只需考虑前min{m,n}行即可,因为第m+1行(如果存在)的首个元素必定比前m行的首个元素更大。