BZOJ 1009 KMP思想 + DP + 矩阵快速幂
2016-01-03 23:05
369 查看
第一次用MarkDown和LaTex,写得有点丑……
本题的坑爹历程给了我一个血的教训:没有真正搞清楚做法之前,不要瞎BB地写题解。不然会造成深陷坑中的严重后果。
题意简述:给定一个字符串s,求出长度为n的不含字串s的字符串t的数量。
这道题是一个非常经典的模型,DP之:
设 f[i][j]为前i个t字符,匹配到s的第 j位(强制选 i)的方案数,则有
ans=Σ( f[n][k] | 0≤k<m )
接下来考虑 f[i][j]的转移:
由于我们是要统计数量,所以我们可以枚举第 i+1位是几。然后自然地,应该转移到(这里亦即贡献到)f[i+1][pos],其中pos为加上这个字符之后,当前串匹配到的位置。
然后我们发现,每一轮i=>i+1的转移都是一样的。对于这样的“无脑”递推,我们可以构造矩阵,然后使用矩阵快速幂来加速。如何构造矩阵呢?我们考虑矩阵元素M[i][j]的意义。它会与当前向量的第j个维度相乘,然后贡献到下一个向量的第i个维度。因此,如果有f[i+1][pos] += f[i][j],就应把M[pos][j]加1。不难发现,处理好这个矩阵之后,它的第0列其实就是初始向量。所以,只需做n次矩阵乘法即可。
代码略丑:
本题的坑爹历程给了我一个血的教训:没有真正搞清楚做法之前,不要瞎BB地写题解。不然会造成深陷坑中的严重后果。
题意简述:给定一个字符串s,求出长度为n的不含字串s的字符串t的数量。
这道题是一个非常经典的模型,DP之:
设 f[i][j]为前i个t字符,匹配到s的第 j位(强制选 i)的方案数,则有
ans=Σ( f[n][k] | 0≤k<m )
接下来考虑 f[i][j]的转移:
由于我们是要统计数量,所以我们可以枚举第 i+1位是几。然后自然地,应该转移到(这里亦即贡献到)f[i+1][pos],其中pos为加上这个字符之后,当前串匹配到的位置。
然后我们发现,每一轮i=>i+1的转移都是一样的。对于这样的“无脑”递推,我们可以构造矩阵,然后使用矩阵快速幂来加速。如何构造矩阵呢?我们考虑矩阵元素M[i][j]的意义。它会与当前向量的第j个维度相乘,然后贡献到下一个向量的第i个维度。因此,如果有f[i+1][pos] += f[i][j],就应把M[pos][j]加1。不难发现,处理好这个矩阵之后,它的第0列其实就是初始向量。所以,只需做n次矩阵乘法即可。
代码略丑:
// BZOJ 1009 KMP+Matrix #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int M=25, N=M; #define rep(i,a,b) for (int i=a; i<=b; i++) #define dep(i,a,b) for (int i=a; i>=b; i--) #define read(x) scanf("%d", &x) #define fill(a,x) memset(a, x, sizeof(a)) int mod; struct Matrix { int n, m, a [M]; void init(int n, int m) { this->n=n; this->m=m; fill(a, 0); } Matrix operator * (const Matrix B) const { Matrix ret; ret.init(B.n, B.n); rep(i,0,n-1) rep(j,0,n-1) rep(k,0,n-1) ret.a[i][j]=(ret.a[i][j]+a[i][k]*B.a[k][j])%mod; return ret; } Matrix operator ^ (const int k) const { Matrix ret, t=*this; ret.n=n; ret.m=m; int tk=k; fill(ret.a, 0); rep(i,0,ret.n-1) ret.a[i][i]=1; while (tk) { if (tk&1) ret=ret*t; t=t*t; tk>>=1; } return ret; } } A; int f[M], n, m; char st[M]; void get_fail() { f[0]=f[1]=0; int j=0; rep(i,2,m) { while (j && st[j+1]!=st[i]) j=f[j]; if (st[j+1]==st[i]) j++; f[i]=j; } } int main() { read(n); read(m); read(mod); scanf("%s", st+1); A.init(m, m); get_fail(); rep(i,0,m-1) rep(j,0,9) { int pos=i; while (pos && st[pos+1]-'0'!=j) pos=f[pos]; if (st[pos+1]-'0'==j) pos++; if (pos!=m) A.a[pos][i]=(A.a[pos][i]+1)%mod; } A=A^n; int ans=0; rep(i,0,m-1) ans=(ans+A.a[i][0])%mod; printf("%d\n", ans); return 0; }
相关文章推荐
- 在Ruby on Rails中使用Markdown的方法
- KMP算法的C#实现方法
- JavaScript中数据结构与算法(五):经典KMP算法
- markdown简介和语法介绍
- Android开发学习笔记之通过API接口将LaTex数学函数表达式转化为图片形式
- 基于Android中dp和px之间进行转换的实现代码
- Android中dip、dp、sp、pt和px的区别详解
- 如何使用Gitblog和Markdown建自己的博客
- LFC1.0.0 版本发布
- Ubuntu12.04 安装LaTex(TexLive+TexMaker+中文环境) 4000
- Android px、dp、sp之间相互转换
- Markdown
- HP data protector软件学习1--基本角色与基本工作流程
- HP data protector软件学习2--软件组成与界面介绍
- Miktex 2.9 + Texmaker 中文显示
- android中像素单位dp、px、pt、sp的比较
- Sublime Text 下的 Mardown 插件