题解:P2679 [NOIP2015 提高组] 子串

老师上课刚讲完这道题,来这里长个估值分享一下,顺便加深记忆。

定义 dp 状态

fi,j,kf_{i,j,k} 表示从字符串 AA 的前 ii 个字符中,取出 kk 个非空子串,拼接后与字符串 BB 的前 jj 个字符相等的方案数。

状态转移

  1. 不取当前字符。
    若第 ii 个字符不属于当前子串,则有 fi,j,k+=fi1,j,kf_{i,j,k}+=f_{i-1,j,k}
  2. 取当前字符, 拼接到新的子串。
    若从位置 ip+1i-p+1ii 的子串等于 Bjp+1:jB_{j-p+1:j} (即子串长度为 pp 且匹配成功),则有 fi,j,k+=fip,jp,k1f_{i,j,k}+=f_{i-p,j-p,k-1}。 

这里 pp 的范围取决于当前 AABB 的匹配情况。

预处理可匹配长度

可以预处理一个二维数组 ycli,jycl_{i,j},表示从 AiA_iBjB_j 开始,最长能匹配的长度,判断 AA 的某段子串与 BB 的某段子串是否匹配。

优化

  1. 接着我们可以发现,每次是修改 fi+1,j+1,k+1f_{i+1,j+1,k+1}fi+p,j+p,k+1f_{i+p,j+p,k+1} 的值,相当于是将一斜行上的值进行修改,所以可以进行差分。
  2. 由于只会从上一状态转移过来,所以可以把 kk 这一维滚掉:
  • fi,jf_{i,j} 表示当前状态。
  • 使用 gi,jg_{i,j} 辅助存储下一状态。
  • 在每次迭代 kk 时,将 ffgg 交换,清空 gg

代码实现

利用CloudflareR2搭建免费图床
服务器脚本分享Invalid Date

评论

评论加载中...