前言
这篇题解是 zak 的做法,我实现得很丑所以常数巨大,但我尽量把我的实现讲清楚()。
做法
转化 & 暴力
首先,令
b i ′ = b a i , c i ′ = c a i b'_i=b_{a_i},c'_i=c_{a_i} b i ′ = b a i , c i ′ = c a i ,就可以将原题条件转换为
b i ′ = a i = c i ′ b'_i=a_i=c'_i b i ′ = a i = c i ′ ,那么对
a i a_i a i 进行单点修改,其实就相当于对
b i ′ b'_i b i ′ 和
c i ′ c'_i c i ′ 都进行单点修改。
对于每一种
b i ′ = a i = c i ′ = w b'_i=a_i=c'_i=w b i ′ = a i = c i ′ = w 的
w w w ,他们的答案数是互相独立互不干扰的,所以可以对每种
w w w 单独考虑对答案的贡献。
设
d p i , 1 / 2 / 3 dp_{i,1/2/3} d p i , 1/2/3 表示考虑前
i i i 个数中,
b p ′ = w / b p ′ = a q = w / b p ′ = a q = c r ′ = w b'_p=w/b'_p=a_q=w/b'_p=a_q=c'_r=w b p ′ = w / b p ′ = a q = w / b p ′ = a q = c r ′ = w 的方案数(
p < q < r ≤ i p<q<r\le i p < q < r ≤ i ),其中
d p i , 0 = 1 dp_{i,0}=1 d p i , 0 = 1 ,则有
d p i , 1 = d p i − 1 , 1 + d p i − 1 , 0 × [ b i ′ = w ] dp_{i,1}=dp_{i-1,1}+dp_{i-1,0}\times [b'_i=w] d p i , 1 = d p i − 1 , 1 + d p i − 1 , 0 × [ b i ′ = w ]
d p i , 2 = d p i − 1 , 2 + d p i − 1 , 1 × [ a i = w ] dp_{i,2}=dp_{i-1,2}+dp_{i-1,1}\times [a_i=w] d p i , 2 = d p i − 1 , 2 + d p i − 1 , 1 × [ a i = w ]
d p i , 3 = d p i − 1 , 3 + d p i − 1 , 2 × [ c i ′ = w ] dp_{i,3}=dp_{i-1,3}+dp_{i-1,2}\times [c'_i=w] d p i , 3 = d p i − 1 , 3 + d p i − 1 , 2 × [ c i ′ = w ]
共有
n n n 种
w w w ,每次修改可能导致
6 6 6 种
w w w 的答案改变,暴力做一次 DP 是
O ( n ) O(n) O ( n ) 的,所以总复杂度是
O ( n 2 + 6 n m ) O(n^2+6nm) O ( n 2 + 6 nm )
由于
d p i dp_i d p i 只依赖于
d p i − 1 dp_{i-1} d p i − 1 ,所以可以空间压缩成
d p 1 / 2 / 3 dp_{1/2/3} d p 1/2/3 ,注意转移顺序。
根号分治:小于等于根号的部分
对
w w w 进行根号分治,统计出
w w w 在
a i , b i ′ , c i ′ a_i,b'_i,c'_i a i , b i ′ , c i ′ 以及修改后,
w w w 的总出现次数
c n t w cnt_w c n t w (显然
∑ c n t w = 3 n m \sum cnt_w=3nm ∑ c n t w = 3 nm )。按照
c n t w cnt_w c n t w 的大小根号分治。
对于出现次数
< B <B < B 的
w w w ,能够有效更改
d p dp d p 的位置不超过
B B B 个,因此每次涉及到修改
w w w 的操作时,暴力重做这一次 DP。
使用动态数组
v e c w vec_w v e c w 存下这
B B B 个位置,当进行修改操作时,相当于往
v e c w vec_w v e c w 里添加或删除位置,暴力找到这个位置进行操作,时间复杂度
O ( B ) O(B) O ( B ) 。
接着考虑维护前缀和,令
f i f_i f i 表示
c i ′ = w c'_i=w c i ′ = w 且符合题意的方案数,则
f i = d p i , 2 × [ c i ′ = w ] f_i=dp_{i,2}\times[c'_i=w] f i = d p i , 2 × [ c i ′ = w ] ,要维护的就是
f i f_i f i 的前缀和。
对序列进行分块,考虑到只需要进行
m m m 次查询,而暴力重新做 DP 本身已经占据了
O ( B ) O(B) O ( B ) 的时间,所以需要
O ( 1 ) O(1) O ( 1 ) 修改,
O ( n ) O(\sqrt n) O ( n ) 查询(这里的根号只是象征义)。令
s i s_i s i 表示块
i i i 的
f f f 的和就可以做到。
根号分治:大于根号的部分
这个 DP 只有四个状态,所以考虑序列动态 DP。
[ d p 0 d p 1 d p 2 d p 3 ] × [ 1 b i ′ = w 0 0 0 1 a i = w 0 0 0 1 c i ′ = w 0 0 0 1 ] = [ d p 0 ′ d p 1 ′ d p 2 ′ d p 3 ′ ] \begin{bmatrix}
dp_0 & dp_1 & dp_2 & dp_3
\end{bmatrix}
\times
\begin{bmatrix}
1 & b'_i=w & 0 & 0 \\
0 & 1 & a_i=w & 0 \\
0 & 0 & 1 & c'_i=w \\
0 & 0 & 0 & 1
\end{bmatrix}
=
\begin{bmatrix}
dp'_0 & dp'_1 & dp'_2 & dp'_3
\end{bmatrix} [ d p 0 d p 1 d p 2 d p 3 ] × 1 0 0 0 b i ′ = w 1 0 0 0 a i = w 1 0 0 0 c i ′ = w 1 = [ d p 0 ′ d p 1 ′ d p 2 ′ d p 3 ′ ]
由于出现次数
> B >B > B 的
w w w 小于
n + m B \frac{n+m}{B} B n + m 个,所以单独考虑每一个
w w w ,
O ( n ) O(n) O ( n ) 维护矩阵前缀乘。
由于枚举每种
w w w 已经消耗了
n \sqrt n n 的时间,查询数有
m m m 个,但是总修改数一定也是
m m m 的级别的(和上面
O ( 6 m n ) O(6mn) O ( 6 mn ) 一样的道理),所以需要做到
O ( 1 ) O(1) O ( 1 ) 查询,
O ( n ) O(\sqrt n) O ( n ) 修改。设
S B i SB_i S B i 表示前
i i i 个块的前缀乘,
S i S_i S i 表示块的左端点到
i i i 的前缀乘,那么查询
r r r 就是
S B b e l r − 1 × S r SB_{bel_r-1}\times S_r S B b e l r − 1 × S r ,修改按照定义修改即可。
取矩阵中的哪个数呢?初始的
[ d p 0 d p 1 d p 2 d p 3 ] \begin{bmatrix}dp_0 & dp_1 & dp_2 & dp_3\end{bmatrix} [ d p 0 d p 1 d p 2 d p 3 ] 是
[ 1 0 0 0 ] \begin{bmatrix}1&0&0&0\end{bmatrix} [ 1 0 0 0 ] ,最终希望得到
d p 3 dp_3 d p 3 ,带进去算可以得到是要矩阵
( 0 , 3 ) (0,3) ( 0 , 3 ) 这个位置的数。
总时间复杂度
O ( ( n + m ) B + 4 3 × n + m B × ( n + m ) ) O((n+m)B+4^3\times \frac{n+m}{B}\times(n+m)) O (( n + m ) B + 4 3 × B n + m × ( n + m )) ,空间复杂度线性,
B B B 可以取
n + m \sqrt{n+m} n + m ,但我取的
B = 1000 B=1000 B = 1000 才能通过()。
我错的一些细节
可能会出现
c n t c i ′ ≤ B cnt_{c'_i}\le B c n t c i ′ ≤ B ,但是修改后的
c n t c i ′ > B cnt_{c'_i}>B c n t c i ′ > B ,这样他就不会重做
c i ′ c'_i c i ′ 的 DP,导致
f i f_i f i 不能被消除贡献。