2026 码蹄杯初赛第一场

Written by: Joyce-Peng-GitHub

码蹄杯初赛第一场

5.

给定矩阵aNm×m, bNn×n (m,nN, mn)a\in\mathbb{N}^{m\times m},\ b\in\mathbb{N}^{n\times n}\ (m,n\in\mathbb{N^*},\ m\geq n),求

(i=0mnj=0mnk=0n1l=0n1(ai+k,j+lbk.l))mod(109+7).\left(\sum_{i=0}^{m-n}\sum_{j=0}^{m-n}\sum_{k=0}^{n-1}\sum_{l=0}^{n-1}(a_{i+k,j+l}\oplus b_{k.l})\right)\bmod(10^9+7).

保证m,n103, (i) (j) (ai,j,bi,j109)m,n\leq10^3,\ (\forall i)\ (\forall j)\ (a_{i,j},b_{i,j}\leq10^9)

按位异或对加法不满足分配律,所以直接化简这个和式是不可能的。考虑按位处理。用x(p)x^{(p)}表示xx从低到高的第pp位。

考虑贡献法,ai,ja_{i,j}与哪些元素进行了异或?于是原和式可以化为

i=0m1j=0m1k=max{i(mn),0}min{i,n1}l=max{j(mn),0}min{j,n1}(ai,jbk,l).\sum_{i=0}^{m-1}\sum_{j=0}^{m-1}\sum_{k=\max\{i-(m-n),0\}}^{\min\{i,n-1\}}\sum_{l=\max\{j-(m-n),0\}}^{\min\{j,n-1\}}(a_{i,j}\oplus b_{k,l}).

kmin=max{i(mn),0}, kmax=min{i,n1},lmin=max{j(mn),0}, lmax=min{j,n1},\begin{array}{c} k_{\min}=\max\{i-(m-n),0\},\ k_{\max}=\min\{i,n-1\},\\ l_{\min}=\max\{j-(m-n),0\},\ l_{\max}=\min\{j,n-1\}, \end{array}

按位考虑,则原和式等于

b=0B1i=0m1j=0m1k=kminkmaxl=lminlmax(ai,j(p)bi,j(p))2p,\sum_{b=0}^{B-1}\sum_{i=0}^{m-1}\sum_{j=0}^{m-1}\sum_{k=k_{\min}}^{k_{\max}}\sum_{l=l_{\min}}^{l_{\max}}(a_{i,j}^{(p)}\oplus b_{i,j}^{(p)})\cdot2^p,

其中B=log(109)B=\lceil\log(10^9)\rceil

对于取定的i,j,pi,j,p,由异或的定义可知,我们只需数出bb在区域N2([kmin,kmax]×[lmin,lmax])\mathbb{N}^2\cap([k_{\min},k_{\max}]\times[l_{\min},l_{\max}])0011的数量即可。当ai,j(p)=0a_{i,j}^{(p)}=0时数11,当ai,j=1a_{i,j}=1时数00。这个计数值可以通过Θ(n2)\varTheta(n^2)预处理二维前缀和来Θ(1)\varTheta(1)求出。

7.

给定a(N)3×n (nN)a\in(\mathbb{N}^*)^{3\times n}\ (n\in\mathbb{N}^*),求

(a0,i/n2a1,i/nmodna2,imodn)i=0n31(a_{0,\lfloor i/n^2\rfloor}\cdot a_{1,\lfloor i/n\rfloor\bmod n}\cdot a_{2,i\bmod n})_{i=0}^{n^3-1}

中最小的mNm\in\mathbb{N}^*项。保证n105, mmin{n3,2n}, (i{0,1,2}) (i) (j) (ai,j105)n\leq10^5,\ m\leq\min\{n^3,2n\},\ (\forall i\in\{0,1,2\})\ (\forall i)\ (\forall j)\ (a_{i,j}\leq10^5)

我真傻,真的。

可以先用a0,a1a_0,a_1组合一遍乘积,用最小的mm个再去与a2a_2组合一遍。这一点我没想到。

用堆维护最小的mm项是很容易想到的。

但这样还不够!暴力组合两个数组,复杂度仍然高达Θ(n2logm)\varTheta(n^2\log m),我们需要找到更高效的寻找最小mm个乘积的方式。很容易想到将它们先排序,然后怎么办?

如果我们将这两个数组组合的过程列成表格(以a0,a1a_0,a_1分别作纵轴和横轴,表格中填上乘积),那末每一行、每一列都必定是递增的。现在我们的任务变为一个经典问题(多路归并问题):如何在这nn行(从列的视角看当然也可以,这是等价的)已经有序的数列中选出最小的mm个?很显然只需对各行维护一个从左往右移动的指针,指向下一个待选元素;每次选取所有待选元素中最小的那一个,并移动指针即可;而“选取所有待选元素中最小的那一个”正适合用一个小根堆来维护。进一步地,由于我们/只需求出最小的mm个元素,我们只需考虑前min{m,n}\min\{m,n\}行即可,因为第m+1m+1行(如果存在)的首个元素必定比前mm行的首个元素更大。