博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【[HNOI2008]GT考试】
阅读量:5253 次
发布时间:2019-06-14

本文共 1500 字,大约阅读时间需要 5 分钟。

我又来复习\(kmp\)

其实这道题主要是一个矩阵乘法,但是\(kmp\)在其中也有着非常重要的作用

我们可以这样定义状态\(dp[i][j]\)表示文本串进行到了\(i\)位置,同时文本串在最后和模式串匹配了一共\(j\)位的方案数

于是答案就是\(\sum_{i=0}^{m-1}dp[n][i]\)

之后我们想一下转移

显然\(dp[i]\)需要从\(i-1\)转移过来

但是怎么转移呢

有一个非常直观也非常\(sb\)的想法就是直接\(dp[i][j]=dp[i-1][j-1]\)

毕竟再补上模式串的第\(j\)位就可以啦

但是转移不止这些

图

那四个画出来的部分是\(next[j]\)

如果我们在转移\(dp[i][j]\)的状态的时候并不让文本串的第\(i\)位和模式串的第\(j\)位相等,而是在这里填上模式串的\(next[j]\)位置上的数

那么很显然\(dp[i-1][nx[j]]+=dp[i-1][j-1]\)

所以我们用\(kmp\)预处理出来一个这样的数组\(a[i][j]\)表示匹配到在模式串上匹配\(j\)\(i\)转移的时候可以填几个数字

所以现在就有

\[dp[i][j]=\sum_{k=0}^{m-1}dp[i-1][k]*a[i][k]\]

显然这是一个矩阵乘法就可以优化的柿子

现在的问题就变成了\(a\)数组怎么求

首先求出\(next\)数组,之后枚举这一位填什么,之后往前跳\(nx\),直到匹配就好了

代码

#include
#include
#include
#define re register#define maxn 21int dp[1001][maxn];char S[maxn];int n,m,mod;int nx[maxn];int ans[maxn][maxn];int a[maxn][maxn];inline void did_a(){ int mid[maxn][maxn]; for(re int i=0;i
=mod) a[i][j]%=mod; }}inline void did_ans(){ int mid[maxn][maxn]; for(re int i=0;i
=mod) ans[i][j]%=mod; }}inline void quick(int b){ while(b) { if(b&1) did_ans(); b>>=1; did_a(); }}int main(){ scanf("%d%d%d",&n,&m,&mod); scanf("%s",S+1); nx[0]=nx[1]=0; for(re int i=2;i<=m;i++) { int p=nx[i-1]; while(p&&S[p+1]!=S[i]) p=nx[p]; if(S[p+1]==S[i]) nx[i]=++p; else nx[i]=0; } for(re int i=0;i

转载于:https://www.cnblogs.com/asuldb/p/10206171.html

你可能感兴趣的文章
IOC容器
查看>>
Windows 2003全面优化
查看>>
URAL 1002 Phone Numbers(KMP+最短路orDP)
查看>>
web_day4_css_宽度
查看>>
用sql删除数据库重复的数据的方法
查看>>
学习笔记21—PS换图片背景
查看>>
electron入门心得
查看>>
格而知之2:UIView的autoresizingMask属性探究
查看>>
Spring3.0 AOP 具体解释
查看>>
我的Hook学习笔记
查看>>
EasyUI DataGrid 中字段 formatter 格式化不起作用
查看>>
海量数据存储
查看>>
js中的try/catch
查看>>
[导入]玫瑰丝巾!
查看>>
自动从网站上面下载文件 .NET把网站图片保存到本地
查看>>
【识记】 域名备案
查看>>
STL uva 11991
查看>>
MY SQL的下载和安装
查看>>
自定义OffMeshLink跳跃曲线
查看>>
寄Android开发Gradle你需要知道的知识
查看>>