把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

题解 CF494B Obsessive String

传送门

题意

给定一个字符串 S,和一个字符串 T

S 中取出任意多个不重叠的子串,使得每个子串都包含 T,求方案数。

分析

先分析一下题目,显然,我们使用 DP 来解决这道题。

设计一个状态:fifi 表示最后一个串的最后一位是 i 的方案数。

我们可以枚举最后一个子串的区间,进行转移。

首先要考虑的是,如何判断区间是否包含 T

我们考虑使用字符串哈希,将整一个匹配串哈希,再标记每一个区间,最后,预处理出当前左侧的第一个匹配串,令其为 Li,因此只要左端点处于 1Lim+1,我们的区间就可以包含 T

p[0]=1;
for(int i=1; i<=n; ++i) p[i]=p[i-1]*P;
for(int i=1; i<=n; ++i) a[i]=a[i-1]*P+s[i];
for(int i=1; i<=m; ++i) wh=wh*P+t[i];
for(int i=m; i<=n; ++i) if(query(i-m+1,i)==wh) mark[i]=1;
for(int i=m; i<=n; ++i) L[i]=mark[i]?i:L[i-1];

枚举了我们这一个区间后,考虑继承前面的 f

令枚举的左端点为 j,右端点为 i

我们的 fi 就可以继承 k[1,j1]f

for(int i=1; i<=n; ++i) {
if(!L[i]) continue;
for(int j=1; j<=L[i]-m+1; ++j) {
f[i]++;
for(int k=1; k<=j-1; ++k) f[i]=(f[i]+f[k])%MOD;
}
}
for(int i=1; i<=n; ++i) tot=(tot+f[i])%MOD;

时间复杂度:O(n3)

接下来考虑优化这个 DP,首先将 k 优化掉。

怎么优化呢,使用前缀和。

for(int i=1; i<=n; ++i) {
if(!L[i]) continue;
for(int j=1;j<=L[i]-m+1;++j) f[i]=(f[i]+qzh[j-1]+1)%MOD;
qzh[i]=(qzh[i-1]+f[i])%MOD;
}

时间复杂度:O(n2)

显然,我们依旧使用前缀和来优化。

for(int i=1; i<=n; ++i) {
if(!L[i]) continue;
f[i]=(sum[L[i]-m]+L[i]-m+1)%MOD;
qzh[i]=(qzh[i-1]+f[i])%MOD;
sum[i]=(sum[i-1]+qzh[i])%MOD;
}

时间复杂度:O(n)

此时就可以愉快的 A 掉此题了。

总结一下,这题的重点其实是在优化 DP 上,还附带了一点点的字符串哈希即可。

posted @   djh0314  阅读(17)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
浏览器标题切换
浏览器标题切换end
点击右上角即可分享
微信分享提示