Digital Patterns
可以看这篇题解
最开始的条件化简应该挺简单的,需要吸收的就是单独考虑\(a,b\)的极长合法子串(没做出来就是因为一直拘泥于二维的正方形,没有想到这个正方形可以映射到\(x\)轴和\(y\)轴的交线)
以题目给的样例为例,\(a\)的极长合法子串的长度为\(1,3\),\(b\)的为\(2,2\)
然后求\(f\)的时候,\(i\)其实就是正方形的大小,然后也不用像题解一样算,直接展开,然后\(x,y\)都是常数,将\(i^2,i\)和常数分开利用公式就好了
update 2026.2.28
居然做出来了,最近有点超模
首先,对\(a,b\)两个序列按照相邻相等元素的点进行划分子串
比如\(a\)是1 1 1 2 3 4 5 5 5 6 6 7 8 9 10 11 12 7 8 9,那么划分出来是1,1,1 2 3 4 5,5,5 6,6 7 8 9 10 11 12 7 8 9,然后统计划分出来的子串的长度
设\(a\)记录出来\(c_1,c_2,...,c_k\),\(b\)记录出来\(d_1,d_2,...,d_l\)(都是单调不减排序),\(e_{i,j}=\min(c_i,d_j)\),\(f_{i,j}=\max(c_i,d_j)\),那么最终答案就是
于是现在考虑怎么维护这个量。为了减少分类讨论,可以将修改操作看作是删除若干个子串,再添加上了若干个子串。比如说原来\(a[l]\ne a[l+1]\)并且\(a[l]\)所在的子串的范围是\([L,R]\),如果现在\(a[l-1]=a[l]+x\),那么就相当于把这个子串给分成了两个子串,删除了一个长度为\((R-L+1)\)的子串,添加了长度为\((l-1)-L+1\)和\(R-l+1\)两个子串,所以我们只需要考虑删除/添加子串对最终的答案的变更量。下面以删除了\(a\)中的一个子串为例
假设删除了\(a\)中的子串长度是\(x\),那么查找到\(d_1,d_2,...,d_l\)中\(x\)的位置,不妨设\(d_i<x\)但\(d_{i+1}>x\),于是删除\(x\)会导致答案减少
通过化简我们可以知道,我们只需要维护\(\{d\}\)的\(\sum\frac{d_i(d_i+1)}{2}\)和\(\sum\frac{d_i(d_i+1)(1-d_i)}{6}\)和\(\sum d_i\)即可
这可以用线段树维护,线段树的范围分别是\([1,n]\)和\([1,m]\),每个点代表\(c\)或者\(d\),分别维护上面三个量即可。但是让GPT 5.2 Thinking写的代码是用的树状数组维护的,也行
然后如果这道题目不止统计正方形,而是可以统计长方形的话,那么做法如下:
经过简单的思考可以想出来,我们对两个序列独立计算下面的量,然后乘起来就是最终的答案
这个量是这么计算的(以\(a\)序列为例):设\(l,r∈[1,n]\)且\(l\le r\),并且\(\forall k∈[l,r),a[k]\ne a[k+1]\);满足这个条件的二元对\((l,r)\)的数目就是要计算的这个量
采用容斥原理,转而去计算满足\(l,r∈[1,n]\)且\(l\le r\),并且\(\exists k∈[l,r),a[k]= a[k+1]\)的\((l,r)\)的数目,然后用二元对的总数减去这个数目就是我们要计算的量
假设给定右端点\(r\),考虑有多少个\(l\)满足。显然我们找到最大的\(l_\max<r\)满足\(a[l_\max]=a[l_\max+1]\),那么就有\(l_\max\)个\(l\)满足。这就是一个维护前驱的操作。假设我们维护好了每一个点的前驱,最后所有点的前驱的和就是我们要减去的数值,于是就可以得到最终要计算的量 现在考虑如何维护前驱。假设现在是对\([l,r]\)的区间整体加\(x\),那么我们只需要考虑\(l-1\)和\(r\)即可
一个naive的想法是分类讨论,但是不想分类讨论的话,就可以看做是先删除一个数再加上一个数 什么意思呢?我们以\(l-1\)为例,无论变化前后\(a[l-1]\)与\(a[l]\)的关系是怎么样的,都可以先看做移除\(a[l-1]\),然后维护前驱,再加上\(a[l-1]\),然后维护前驱
当我们移除\(a[l-1]\)的时候(下面的\(a[l]\)是没有加上\(x\)的):
- 假设\(a[l-1]\ne a[l]\),那么移除了不会有任何变化 * 假设\(a[l-1]=a[l]\),那么移除后,我们要把以\(l-1\)作为\(l_\max\)的所有的\(r\)的前驱变换一下。这就需要我们维护所有的\(l_\max\)(假设我们用一个STL的set\(S\)维护,那么一定有\(l-1∈S\)),找到\(l-1\)在\(S\)中的前驱\(\text{pre}\)和后缀\(\text{nxt}\),那么我们需要把\([l,\text{nxt}]\)的前驱从\(l-1\)改成\(\text{pre}\),并且从\(S\)中移除\(l-1\)
当我们加上\(a[l-1]\)的时候:
- 假设\(a[l-1]\ne a[l]+x\),那么加上其他点不会变化,我们只需要维护\(l-1\)的前驱,此时只需要在\(S\)中去查找即可 * 假设\(a[l-1]=a[l]\),那么加上后,我们首先将\(l-1\)加入\(S\),然后找到其在\(S\)中的前驱\(\text{pre}\)和后缀\(\text{nxt}\);\(l-1\)的前驱就是\(\text{pre}\),\([l,\text{nxt}]\)的前驱就是\(l-1\)
对于\(a[r]\)是同理的操作
上面的操作可以用线段树来维护

浙公网安备 33010602011771号