【题解】UOJ Long Round #1
// created on 22.09.22
A. 多线程计算
我们首先注意到:考虑给每个位置确定一个排名,那么排名之间的空隙大小期望是 \(\frac{1}{n\times m+1}\) 的。
令 \(f_{k,i,j}\) 表示插入排名前 \(k\) 的位置,恰好有 \(i\) 行 \(j\) 列填满的方案数:
其中 \(k!(nm-k)!\) 是关于 \(k\) 的常系数。如果我们设计 \(g_{i,j}\) 表示至少有 \(i\) 行 \(j\) 列填满的贡献和,同时令 \(f_{i,j}\) 也为贡献和,那么 \(f_{i,j}\) 可以通过 NTT 优化从 \(g_{i,j}\) 带上容斥系数求得,而 \(g_{i,j}\):
发现是卷积的形式:第 \(k-im-jn+ij\) 项和第 \(k\) 项组合,得到第 \(im+jn-ij\) 项。对于 \(im+jn-ij\) 相等的 \((i,j)\) 贡献是不变的。于是只需要 NTT 求 \(g_{i,j}\),关于容斥系数,只需要两维依次考虑即可。
远古提交记录:Submission #449630 - Universal Online Judge (uoj.ac)。
B. 光伏元件
首先对于 \(C_{i,j}=-1\) 的相当于代价 \(+\infty\) 。我们将所有 \(A_{i,j}\) 翻转过来,并同时反转 \(C_{i,j}\),使得初始局面是全 \(0\) 的。接着设 \(x_{i,j}\) 表示 \((i,j)\) 最终的状态,我们有:
变量个数 \(n^2\),约束条数 \(6n\) 。和线性规划套路中的网络流模型不贴近。事实是,我们清楚地知道 \(x\in[0,1]\),为什么不直接设计网络流呢?
我们考虑 \(k=0\) 的情况,用循环流限制流量相等:对于 \((i,j)\) 从行 \(i\) 向列 \(j\) 连边。要求行 \(i\) 和列 \(i\) 的出入度一样,就从列 \(i\) 向行 \(i\) 连边,这条边的流量就是他们的 \(c\) 。求解最小费用循环流就行了。
对于一般情况,我们考虑:新建原汇,假设源汇到 \(i,i'\),以及 \(i'\rightarrow i\) 的流量分别为 \(a,b,x\),那么 \(i\) 的出流量为 \(x+a\),而 \(i'\) 的入流量为 \(x+b\) 。我们只需要令 \(a,b\in[0,k],x\in[l,r-k]\) 就可以组合出所有合法的流方式,并且对应的所有流都是合法的。当 \(r-l<k\) 时相当于没有 \(k\) 的限制,只需要限制一下 \(i,i'\) 的上下界就行。
提交记录:Submission #584607 - Universal Online Judge (uoj.ac)。
总结一下,建图比较平凡,而关于流量限制,考虑我们的实际流量是什么,关于单点就用源汇限制,关于双点就建反边限制。总体仍然是围绕 "合法流函数满足任意点的出入度一样" 进行的。
C. 服务器调度
一个点到点集最远的肯定是点集直径端点,如果没有修改的话,只需要考虑直径端点将树分成了两个部分,而两个部分对应了 DFN 序列上的 \(O(1)\) 段区间。顺序扫描将所有点的答案求出即可。
到了 Subtask 4 我们只关心距离和,那么贡献可以通过 "到根距离之和减去重复路径长度" 计算 —— 前者很简单,而后者讨论每条边的贡献,也仅仅相当于在祖先链上求个和。每次更新点集直径就重新考虑贡献。
接下来考虑原问题,仍然讨论每条边的贡献,每次通过倍增找到直径中间的分界点,最后的问题可以化为给边打标记。此时发现查询时边的贡献可以拆成两部分,一部分是祖先链,一部分是子树内,两部分都可以通过链分治加线段树完成。
提交记录: Submission #584643 - Universal Online Judge (uoj.ac)。
总结一下,我感觉这题没啥营养。
顺带一题,上述提交记录中第一次实现了 DFN 序上的 \(O(1)\) LCA —— 常数比欧拉序小。
D. 打击复读
本来觉得不太可能直接 SAM,于是想到是 SA,不过差一个地方一直不会,结果又发现是带修的。
那做个毛线,考虑翻转问题。然后建 SAM,答案为:
可以发现 \(i-L_u+1\) 和 \(i-R_u\) 可以拆开算。对于 \(i-L_u+1\) 的话,如果建立反串的 SAM,就只需要定位 \(S[i-L_u+1,i]\),然后 \(\sum\limits_{i\in \mathbf{endpos}_u}S_{i-L_u+1}\) 就是 \(\sum\limits_{i\in \mathbf{endpos}'_u}S_{i}\) 。
于是问题变成了对所有的 \(S[i-L_u+1,i]\) 定位。串定位是简单的。
因为代码实现并不难,所以这里就不写了。
总结一下,这题其实很诈骗 .. 但是在一定的时间内没做出来,主要问题出在没注意带修,然后故意避开 SAM 去想 SA 。不过,如果按照常规思路思考一下 SAM,然后发现其修改的只是左权值,就可以发现修改和 SAM 的结构相性极佳,从而翻转一下串,一下就做完了。
E. 校验码
考虑将 \(i\) 写成 \(d_i^2t_i\),\(j\) 同理,有:
问题变成,对于 \(d\in[1,n]\) 求解:
对每个 \(d\) Min25 算理论复杂度好像可行,但是我们完全没用到其他性质!
令 \(g(n,d)=\sum\limits_{i=1}^{n}\mu(id)^2S\left(\sqrt{\lfloor\frac{n}{i}\rfloor}\right)\),要求的就是 \(g(\lfloor\frac{m}{d}\rfloor,d)\) 。而对于 \(g(n,d)\) 来说有:
在考虑递推的形式之前,先来考虑一下初值怎么求:即求 \(g(n,1)=\sum\limits_{i=1}^{n}\mu(i)^2S\left(\sqrt{\lfloor\frac{n}{i}\rfloor}\right)\) 。而在这个基础上需要处理 \(\mu(i)\) 的前缀和,对于这点易知 \(\sum\limits_{i=1}^{n}\mu(i)^2=\sum\limits_{i=1}^{\sqrt{n}}\mu(i)\lfloor\frac{n}{i^2}\rfloor\) 。回到原问题 \(g(n,1)\),最后用到的肯定形如 \(n=\lfloor\frac{m}{d}\rfloor\) 。在一定范围内预处理,剩下的范围整除分块即可。
接下来我们考虑 \(g(n,d)\) 的状态数,考虑预处理出所有 \(d\leq m^{\frac{1}{3}}\) 的状态,状态数并不是很多。对于剩下的 \(d>\frac{1}{3}\) 的情况,递推的层数很少。
附 1:对于 \(\sqrt{\lfloor\frac{n}{i}\rfloor}\) 的整除分块有:令 \(k=\sqrt{\lfloor\frac{n}{i}\rfloor}\),那么找到最大的 \(r\) 使得 \(\sqrt{\lfloor\frac{n}{r}\rfloor}\geq k\),也即 \(\lfloor\frac{n}{k^2}\rfloor\geq r\) 。对于 \(\lfloor\frac{n}{i^2}\rfloor\) 的整除分块有:令 \(k=\lfloor\frac{n}{i^2}\rfloor\),那么找到最大的 \(r\) 使得 \(\lfloor\frac{n}{r^2}\rfloor\geq k\),也即 \(\lfloor\frac{n}{k}\rfloor \geq r^2\) 。
附 2:具体实现的时候,\(g(n,d)\) 的实际状态数只有 \(3.6\times 10^7\) 级别,而主要瓶颈在 \(g(n,1)\) 而不在转移。因此只需要考虑 \(g(n,1)\) 的求法(如果硬求是 \(m^{\frac{5}{6}}\),只能过 80pts)。如果我们能对 \(m^{\frac{2}{3}}\) 范围内预处理,剩下的值只有 \(m^{\frac{1}{3}}\) 个,再整除分块就是 \(m^{\frac{2}{3}}\) 的了。
于是考虑 \(g(n,1)-g(n-1,1)=\sum\limits_{i=1}^{n}\mu(i)^2\left(S\left(\sqrt{\lfloor\frac{n}{i}\rfloor}\right)-S\left(\sqrt{\lfloor\frac{n-1}{i}\rfloor}\right)\right)\),只有在 \(\sqrt{\lfloor\frac{n}{i}\rfloor}\) 与 \(\sqrt{\lfloor\frac{n-1}{i}\rfloor}\) 不同时才有效。这样的情况发生当且仅当 \(\lfloor\frac{n}{i}\rfloor\) 是 \(d^2\) 且 \(i|n\) 。
附 3:更优一步可以考虑预处理 \(g(n,d),nd\leq B\),\(B\) 是一个阈值。其中 \(g(n,d)=\sum\limits_{i=1}^{n}\mu(id)^2S\left(\sqrt{\lfloor\frac{n}{i}\rfloor}\right)\),仍然考虑到 \(g(n,d)-g(n-1,d)=\sum\limits_{i=1}^{n}\mu(id)^2\left(S\left(\sqrt{\lfloor\frac{n}{i}\rfloor}\right)-S\left(\sqrt{\lfloor\frac{n-1}{i}\rfloor}\right)\right)\),同样处理即可。这种递归计算的东西底层预处理点东西总是有好处的。
提交记录:Submission #584789 - Universal Online Judge (uoj.ac)。
总结一下,前半部分拆贡献莫反都比较基础,后半部分在算 \(f(d)\) 的时候我没有得到好的做法。Sol 的做法是直接用 \(g(n,d)\) 表示出那个式子,然后根据后续变化发现子问题模型。接着大胆搜一下状态发现状态数远比想象的少,然后优化求 \(\mu(x)^2\) 前缀和,再在 \(g(n,d)\) 的底层用一种批量处理的方式进行提前处理。
关键点还是在于列 \(g(n,d)\) 发现子问题,然后搜状态。以后遇见这种两维的计算函数不要不敢列出来 .. 其实直接毛咕咕发现状态数大概就有可以松的痕迹,再搜一下验证一下就大功告成了。
F. 卫星基站建设
咕了。