讲解
转化一下题目的要求,假设我们知道点$(i,j)$的上下左右的常青树的个数分别为$U[i][j]$,$D[i][j]$,$L[i][j]$和$R[i][j]$,那么依据一个很简单的组合数学我们知道:
其中$C$为组合。基本的思路就是这样,但是我们要考虑优化。
从空间上来说,$1 \leq N, M \leq 1000000000$,肯定会直接爆炸(并且空间限制还是$128MB$)。题目并不要求十分确切的常青树位置,因此可以直接离散化。于是我们可以将坐标离散到一个$W \times W$的图中,因为$1 \leq W \leq 10000$,因此空间的问题就直接解决了。
然后是时间,对于每一个墓地,原始做法是$O(N^2)$的求出上下左右的四个数组,但是最终的时间复杂度是$O(N^4)$。于是对于优化来说这里用到一个扫描线的思想。
对于扫描线的具体讲解可以直接$Google$,这里只是针对题目讲方法罢了。
将所有的常青树按照$X$为第一关键字,$Y$为第二关键字的方法升序排序。
对于同一行的两个常青树,如果中间没有任何常青树,那么发现中间的所有的墓地的$L[i][j]$和$R[i][j]$都相等,因此只需要前缀和预处理出来
即可,下面要求的就只剩下了$U[i][j]$和$D[i][j]$。
维护上下所有常青树的乘积,而左右乘积的改变次数就等于常青树的个数,而考虑其他行的时候上下乘积的改变次数也就是常青树的个数。
于是我们要维护上下组合数的乘积的区间和,这种维护显然就可以线段树或者树状数组。
步骤
对于同一行的两个数$A$和$B$,$Ans += C_{k}^{L[A]} \times C_{k}^{R[B]}$,然后用树状数组维护$A$和$B$点的$C_{k}^{U[i]} \times C_{k}^{D[i]}$的和。(省略掉了列,因为是同一行嘛)
答案实际上就是
从左向右处理的时候,修改树状数组该点横坐标位置上的数值为
代码
1 |
|
后记
有人说可不可以搞一个二维线段树,思路上来说是可行的,但是空间上大概会爆炸吧~。
最后在冲浪的时候发现由于模数为$2147483647$所以可以自然溢出然后最后$ \& 2147483646$就可以了。