题解:P6692 出生点
题目要求把所有合法出生点二元组的曼哈顿距离求和,对质数 \(p=10^{9}+7\) 取模。曼哈顿距离可以拆分成横、纵两轴之差的绝对值之和,因此总答案就是行方向贡献与列方向贡献之和。以下叙述行方向,列方向对称地交换 \(n,m\) 与 \(x,y\) 即可。
设第 \(i\) 行可用格子数为 \(f_i\)。行方向的目标式子是 \(\sum_{i<j}(j-i)f_i f_j\)。
把行按坐标升序扫描并维护两项前缀量 \(S_1=\sum f_i, S_2=\sum i f_i\)。
当新行 \(j\) 到来时,它与已处理部分产生的增量为 \((jS_1-S_2)f_j\),同时更新 \(S_1,S_2\)。如果就这么逐行做,复杂度会是 \(O(n)\) 而 \(n\le10^{9}\) 不能接受。观察到除了含有障碍的极少行,其余整段行的 \(f_i\) 全相等且都等于 \(m\),于是可以把这些连续纯净区间整体处理。
把含障碍的行坐标排好序为 \(v_1<v_2<\dots<v_t\)(\(t\le k\))。连续无障碍区间记为 \([L,R]\),长度 \(\ell=R-L+1\)。该区间内自身贡献是 \(m^2\binom{\ell}{2}=m^2\frac{\ell(\ell-1)}{2}\)。
它与所有已处理行之间的贡献需用到 \(\sum_{r=L}^{R}r=\frac{\ell(L+R)}{2}\)。
从而可以一次性计算,与逐行扫描的更新公式完全一致,只是把长度与等差数列求和一次套进去。因为区间与单独行都只要 \(O(1)\) 处理,整条扫描的时间主要耗在排序和统计障碍数上。
障碍数统计方法是把障碍数组按 \(x\) 排序,一趟扫描即可获得每个 \(x\) 出现次数 \(c\),于是 \(f_x=m-c\)。列方向再按 \(y\) 排序做一次即可得到列贡献。
函数 \(\text{calc}\) 负责一维扫描:输入坐标数组 \(\{v_s\}\) 及同长权数组 \(\{f_s\}\),外加总行(或列)数 \(N\) 与默认权 \(F_0\)。它维护前缀 \(s_1,s_2\),遇到纯净区间先计算区间内部加区间对前缀的贡献,再批量更新 \(s_1,s_2\);遇到含障碍单行直接按公式更新。所有乘法都在模 \(p\) 下进行;区间内部自乘系数用到 \(\tfrac12,\tfrac16\) 的逆元。
最终答案是两次调用 \(\text{calc}\):一次行向、一次列向,结果相加再模 \(p\)。
时间复杂度 \(O(k\log k)\)。