重复的串:KMP + dp 的板子题。

暴力 dp

设计 \(dp_{k,i,j}\) 表示主串匹配到第 \(i\) 位,模式串有 \(j\) 位已匹配完成,目前已完成 \(k\) 次匹配的方案数。

不难写出暴力的填表法转移式子,发现是平方级别的转移,所以使用填表法不行,我们尝试刷表法。

\(dp_{k,i,j}\) 要转移去的地方显然是第 \(i+1\) 位,于是我们要观察 \(j\) 里哪些是合法的,很容易就想到用 KMP 加速这个过程,因为 KMP 做的也是匹配到某一位后,求出下一位的最大匹配长度。

假设 \(m\) 为模式串的长度。

对于 \(dp_{k,i,j}\) 我们枚举第 \(i+1\) 位的字符是什么,依次和当前需要匹配的字符进行比较,然后用 KMP 的 next 数组求出下一位的最大匹配长度 \(l\):

  • 当最大匹配长度为 \(m\) 时,这时候 \(k\) 就要 \(+1\),所以 \(dp_{k+1,i+1,next_l} \gets dp_{k+1,i+1,next_l}+dp_{k,i,j}\)。
  • 当最大匹配长度小于 \(m\) 时,直接转移即可,\(dp_{k,i+1,l} \gets dp_{k,i+1,l}+dp_{k,i,j}\)。

时间复杂度是 \(O(k|\sum|n)\) 的,显然不可过。

矩阵优化

发现当值域非常大的 \(i\) 确定时,剩下两维的数量很小,只有 \(90\) 个值左右,考虑矩阵优化 dp。

我们把 \(i\) 这一位提取到前面来,作为快速幂的幂次即可。

构造矩阵有点难描述,看代码吧,大体就是做一遍上面的那个转移,注意细节问题就好了。

另外,当 \(j=m\) 时,不能进行转移。

时间复杂度 \(O((k|\sum|)^3 \log n)\)。

关于完整匹配

本题中,完整匹配后可以跳到 \(next\) 处,是因为这样统计方案不会重复。而其他题中,有时候完整匹配是不能直接跳回 \(next\) 的,因为完全匹配后和 \(next\) 的情况可能是不同的。这时候就要对 \(next\) 进行转移,其实就不用特判 \(next\) 就行了,下次它会自己跳回去自己的 \(next\) 的。

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define lc (p<<1)
#define rc ((p<<1)|1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pi;
const ll mod=998244353;
int n,ne[35],m;
char c[35];
struct mat{
ll a[105][105];
mat(){memset(a,0,sizeof(a));}
mat operator*(const mat &t)const{
mat res;
for(int i=0;i<=100;i++)
{
for(int k=0;k<=100;k++)
{
for(int j=0;j<=100;j++)
{
res.a[i][j]=(res.a[i][j]+a[i][k]*t.a[k][j])%mod;
}
}
}
return res;
}
};
void construct_dp(mat &dp)
{
for(int lv=0;lv<=2;lv++)
{
int ns=1+lv*(m+1);
for(int i=ns;i<ns+m;i++)
{
for(int j=0;j<26;j++)
{
char nc=('a'+j);
int now=i-ns;
while(now&&nc!=c[now+1])now=ne[now];
if(nc==c[now+1])now++;
if(now==m)
{
if(lv==2)continue;
now=ne[now];
dp.a[i][ns+m+1+now]=(dp.a[i][ns+m+1+now]+1)%mod;
}
else dp.a[i][ns+now]=(dp.a[i][ns+now]+1)%mod;
}
}
}
}
void construct_init(mat &s){s.a[1][1]=1;}
mat qpow(mat a,ll b)
{
mat res;
for(int i=0;i<=100;i++)res.a[i][i]=1;
while(b)
{
if(b&1)res=res*a;
a=a*a;
b>>=1;
}
return res;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>c+1>>n;
m=strlen(c+1);
int now=0;
for(int i=2;i<=m;i++)
{
while(now&&c[now+1]!=c[i])now=ne[now];
if(c[now+1]==c[i])now++;
ne[i]=now;
}
mat dp;
construct_dp(dp);
mat s;
construct_init(s);
dp=s*qpow(dp,n);
ll ans=0;
for(int i=1+2*(m+1);i<1+3*(m+1);i++)ans=(ans+dp.a[1][i])%mod;
cout<<ans;
return 0;
}

Luogu P10581 蓝桥杯2024国A 重复的串 题解 [ 蓝 ] [ KMP ] [ 动态规划 ] [ 矩阵加速 ]的更多相关文章

  1. 平方十位数(蓝桥杯第八届国赛真题 JAVA-B组)

    思路:从大到小枚举,判断其平方是否不重复 答案:9814072356 //水题 标题:平方十位数 由0~9这10个数字不重复.不遗漏,可以组成很多10位数字. 这其中也有很多恰好是平方数(是某个数的平 ...

  2. P8701 [蓝桥杯 2019 国 B] 第八大奇迹

    简要题意 你需要维护一个长度为 \(L\) 的序列 \(a\),初始时全部都是 \(0\),有 \(N\) 个操作,支持: C p x,将 \(a_p\) 修改为 \(x\). Q a b,输出 \( ...

  3. P8622 [蓝桥杯 2014 国 B] 生物芯片

    简要题意 有 \(N\) 个二进制数,编号为 \(1\sim N\),初始时都是 \(0\).博士进行了 \(N-1\) 次操作,在第 \(i\) 次操作时,会将 \(1\sim N\) 中所有编号为 ...

  4. P8618 [蓝桥杯 2014 国 B] Log 大侠

    简要题意 给你一个长度为 \(n\) 的正整数序列 \(a\),有 \(m\) 个询问,每一个询问给出一个区间 \([l,r]\).定义函数 \(f(x)=\lfloor\log_{2}(x)+1\r ...

  5. P8796 [蓝桥杯 2022 国 AC] 替换字符

    题面 给定一个仅含小写英文字母的字符串 \(s\) 和 \(m\) 次操作,每次操作选择一个区间 \([l_i,r_i]\) 将 \(s\) 的该区间中的所有字母 \(x_i\) 全部替换成字母 \( ...

  6. 算法笔记_106:蓝桥杯练习 算法提高 周期字串(Java)

    目录 1 问题描述 2 解决方案 2.1 第一印象解法(80分) 2.2 借鉴网友解法(100分)   1 问题描述 问题描述 右右喜欢听故事,但是右右的妈妈总是讲一些“从前有座山,山里有座庙,庙里有 ...

  7. [蓝桥杯]ALGO-87.算法训练_字串统计

    问题描述 给定一个长度为n的字符串S,还有一个数字L,统计长度大于等于L的出现次数最多的子串(不同的出现可以相交),如果有多个,输出最长的,如果仍然有多个,输出第一次出现最早的. 输入格式 第一行一个 ...

  8. 2019年第十届蓝桥杯c++A组java/c++组题解

    #include<iostream> #include<vector> using namespace std; vector <int > vec; long l ...

  9. 2018年蓝桥杯B组C/C++决赛题目

    自己的博客排版,自我感觉略好一点. 先放上题目. 点击查看2018年蓝桥杯B组C/C++决赛题目题解     1.换零钞 x星球的钞票的面额只有:100元,5元,2元,1元,共4种. 小明去x星旅游, ...

  10. 2019年第十届蓝桥杯国赛总结(JavaA组)

    JavaA组国二,可以报销了~ JA死亡之组可不是盖的,rank12的排名还是拿不到国一啊(只有五个.. 出成绩的一刻波澜不惊,毕竟去年有国一了不慌哈哈哈 不过对我来说这个结果还算意料之外吧,毕竟大三 ...

随机推荐

  1. 在vue中使用XLSX导出表格

    安装依赖 npm install file-saver xlsx -S 然后在需要的页面中引入依赖包 import FileSaver from 'file-saver'; import XLSX f ...

  2. onlyoffice

    https://helpcenter.onlyoffice.com/installation/docs-enterprise-install-centos.aspx?_ga=2.51626159.76 ...

  3. uniapp+django 新手学习步骤记录 (1)

    第一次学习uniapp和django,找了一个入门教程遇到坑,记录一下. 1.Django项目和uni-app项目的创建及项目文件讲解_慕容星言的博客-CSDN博客 (1)注意同时安装了python2 ...

  4. 钉钉机器人发送信息shell

    #钉钉机器人发送信息shell 可作为shell函数模块调用,用于监控警报.jenkins发版通知等 微信API官方文档 https://ding-doc.dingtalk.com/doc#/serv ...

  5. 评 PowerShell

    近来不得不接触 pwsh,发现竟然设计的这么漂亮. pwsh 的设计出发点:pwsh 的命令都是面向对象的,命令返回的是对象,命令传入的也是对象.对象在命令的管道间传递,从而组合出复杂任务. 这和 l ...

  6. merging rhino 哈哈

  7. 【网站搭建】Docsify+Gittalk的配置过程记录分享。原创!

    Gittalk 配置 这个不一定最先配置,我也不建议你最先配置这个,这个最好最后配置. 萌狼蓝天把这个的配置写在第一条,是因为我在这折腾了很久,就是因为网上抄来抄去的答案,除了迷惑萌狼蓝天难以给萌狼蓝 ...

  8. arch 音频处显示没有输入或输出设备

    我的设备是 Dell G15 5511, 属于比较新的设备, 查看了 Fourm 与 wiki 后使用 1 yay -S sof-firmware   安装框架之后重启即可使用.

  9. maven常见命令之 -pl -am -amd

    昨天maven的deploy任务需要只选择单个模块并且把它依赖的模块一起打包,第一时间便想到了-pl参数,然后就开始处理,但是因为之前只看了一下命令的介绍,竟然花了近半小时才完全跑通,故记录此文. 假 ...

  10. Qt编写的项目作品11-带频谱的音乐播放器

    一.功能特点 可获取整个声音文件采样值数据 可实时获取当前播放位置的采样值数据 可设置采样的步长和数量 可开始播放/暂停播放/停止播放 多线程处理,超流畅 可设置当前播放位置 可设置和调节音量 支持任 ...