Luogu P10581 蓝桥杯2024国A 重复的串 题解 [ 蓝 ] [ KMP ] [ 动态规划 ] [ 矩阵加速 ]
重复的串: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 ] [ 动态规划 ] [ 矩阵加速 ]的更多相关文章
- 平方十位数(蓝桥杯第八届国赛真题 JAVA-B组)
思路:从大到小枚举,判断其平方是否不重复 答案:9814072356 //水题 标题:平方十位数 由0~9这10个数字不重复.不遗漏,可以组成很多10位数字. 这其中也有很多恰好是平方数(是某个数的平 ...
- P8701 [蓝桥杯 2019 国 B] 第八大奇迹
简要题意 你需要维护一个长度为 \(L\) 的序列 \(a\),初始时全部都是 \(0\),有 \(N\) 个操作,支持: C p x,将 \(a_p\) 修改为 \(x\). Q a b,输出 \( ...
- P8622 [蓝桥杯 2014 国 B] 生物芯片
简要题意 有 \(N\) 个二进制数,编号为 \(1\sim N\),初始时都是 \(0\).博士进行了 \(N-1\) 次操作,在第 \(i\) 次操作时,会将 \(1\sim N\) 中所有编号为 ...
- P8618 [蓝桥杯 2014 国 B] Log 大侠
简要题意 给你一个长度为 \(n\) 的正整数序列 \(a\),有 \(m\) 个询问,每一个询问给出一个区间 \([l,r]\).定义函数 \(f(x)=\lfloor\log_{2}(x)+1\r ...
- P8796 [蓝桥杯 2022 国 AC] 替换字符
题面 给定一个仅含小写英文字母的字符串 \(s\) 和 \(m\) 次操作,每次操作选择一个区间 \([l_i,r_i]\) 将 \(s\) 的该区间中的所有字母 \(x_i\) 全部替换成字母 \( ...
- 算法笔记_106:蓝桥杯练习 算法提高 周期字串(Java)
目录 1 问题描述 2 解决方案 2.1 第一印象解法(80分) 2.2 借鉴网友解法(100分) 1 问题描述 问题描述 右右喜欢听故事,但是右右的妈妈总是讲一些“从前有座山,山里有座庙,庙里有 ...
- [蓝桥杯]ALGO-87.算法训练_字串统计
问题描述 给定一个长度为n的字符串S,还有一个数字L,统计长度大于等于L的出现次数最多的子串(不同的出现可以相交),如果有多个,输出最长的,如果仍然有多个,输出第一次出现最早的. 输入格式 第一行一个 ...
- 2019年第十届蓝桥杯c++A组java/c++组题解
#include<iostream> #include<vector> using namespace std; vector <int > vec; long l ...
- 2018年蓝桥杯B组C/C++决赛题目
自己的博客排版,自我感觉略好一点. 先放上题目. 点击查看2018年蓝桥杯B组C/C++决赛题目题解 1.换零钞 x星球的钞票的面额只有:100元,5元,2元,1元,共4种. 小明去x星旅游, ...
- 2019年第十届蓝桥杯国赛总结(JavaA组)
JavaA组国二,可以报销了~ JA死亡之组可不是盖的,rank12的排名还是拿不到国一啊(只有五个.. 出成绩的一刻波澜不惊,毕竟去年有国一了不慌哈哈哈 不过对我来说这个结果还算意料之外吧,毕竟大三 ...
随机推荐
- Yii2之model
记录model常用方法 between: $model->andFilterWhere(['between','apply_time',$startTime,$endTime])
- pip之常见错误汇总
基本使用: 1.安装文件中的包 pip install -r requirements.txt 问题: 1. pip._vendor.urllib3.exceptions.ReadTimeoutErr ...
- Java设计模式——职责链模式:解锁高效灵活的请求处理之道
嘿,各位 Java 编程大神和爱好者们!今天咱们要一同深入探索一种超厉害的设计模式--职责链模式.它就像一条神奇的"处理链",能让请求在多个对象之间有条不紊地传递,直到找到最合适的 ...
- WxPython跨平台开发框架之用户选择和标签组件的设计
在系统的权限管理中,往往都会涉及到用户的选择处理,特别是基于角色的访问控制中,很多情况下需要用到选择用户的处理.本篇随笔,基于WxPython跨平台开发框架,采用原有开发框架成熟的一套权限系统理念,对 ...
- Docker安装最新版MySQL
下载docker dnf -y install docker 下载mysql镜像 docker pull mysql 运行Mysql mkdir -p /home/mysql/data docker ...
- 安卓导出已安装app的apk
安卓导出已安装应用APK 有时候想看看别人的APK里面的资源文件或者是逆向,首先就得先搞到APK文件 两种方法获取手机上已安装应用的APK文件 通过adb命令 首先把目标手机连接上电脑 在终端输入 a ...
- manim边学边做--同伦变换
在Manim中,移动一个元素除了之前介绍的方法之外,还可以通过同伦运算来移动一个元素. 与普通的移动元素方式相比,使用同伦运算移动一个元素时,实际上是在考虑整个空间的连续变形过程中元素的相应变化. 这 ...
- Qt开源作品42-视频监控布局
一.前言 自从做监控系统以来,就一直有打算将这个功能独立出来一个类,这样的话很多系统用到此类布局切换,通用这个类就行,而且后期此布局会增加其他异形布局,甚至按照16:9之类的比例生成布局,之前此功能直 ...
- 揭秘百度IM消息中台的全量用户消息推送技术改造实践
本文内容由百度技术团队分享,原题"基于公共信箱的全量消息实现",为了帮助理解,有较多修订.内容重组和重新排版. 1.引言 百度的IM消息中台为百度APP以及厂内百度系产品提供即时通 ...
- Pytorch损失函数总结
损失函数 nn.L1Loss 创建一个衡量输入中每个元素之间的平均绝对误差 (MAE) 的标准XX和目标是的是的. nn.MSELoss 创建一个标准,用于测量输入中每个元素之间的均方误差(平方 L2 ...