题目地址:

https://www.acwing.com/problem/content/1054/

你现在需要设计一个密码SSS,SSS需要满足:SSS的长度是NNN;SSS只包含小写英文字母;SSS不包含子串TTT;例如:abcabcabc和abcdeabcdeabcde是abcdeabcdeabcde的子串,abdabdabd不是abcdeabcdeabcde的子串。请问共有多少种不同的密码满足要求?由于答案会非常大,请输出答案模109+710^9+7109+7的余数。

输入格式:
第一行输入整数NNN,表示密码的长度。第二行输入字符串TTT,TTT中只包含小写字母。

输出格式:
输出一个正整数,表示总方案数模109+710^9+7109+7后的结果。

数据范围:
1≤N≤501≤N≤501≤N≤50
1≤∣T∣≤N1≤|T|≤N1≤∣T∣≤N,∣T∣|T|∣T∣是TTT的长度。

字符串匹配的过程可以用状态机来模拟。实际上KMP算法就是在模拟一种状态机,该状态机是依据模式串生成,并且可以接受以模式串为子串的任意字符串。即,我们先由模式串生成KMP里的next数组,接着用这个数组构造出一个有限状态自动机,使得这个DFA(Deterministic Finite Automaton,确定有限状态自动机的英文缩写)只接受以该模式串为子串的字符串。我们以字符串"aba"为模式串举例,具体来说如下:
1、先求出s = "aba"的next数组。参考https://blog.csdn.net/qq_46105170/article/details/113805346。这里的next数组可以是未优化版的也可以是优化版的,因为本质上来说,它们构造出的DFA识别的语言是一样的。
2、构造一个DFA,它有三个状态,分别是0,1,2,30,1,2,30,1,2,3,000是初始状态,333是接受状态(该DFA只有一个接受状态)。先构造边δ(0,a)=1,δ(1,b)=2,δ(2,a)=3\delta(0,a)=1,\delta(1,b)=2,\delta(2,a)=3δ(0,a)=1,δ(1,b)=2,δ(2,a)=3,这三个转移边是显然的,对应的情况是恰好存在子串"aba"。接下来考虑失配边,这个字符串的next数组是ne=[−1,0,0]n_e=[-1,0,0]ne​=[−1,0,0],这个数组规定了如果在s[i]s[i]s[i]存在失配,应该如何跳转。跳转规则如下:比如在s[1]s[1]s[1]和s[2]s[2]s[2]处失配的时候(对应的是当前状态在111和222的时候,比如当前位于状态111,然后读入了'a'字符,这样就发生了失配),比如当前读到的字符是'c',那么就回到状态000,然后继续在状态000处匹配'c'(也就是看一下s[0]s[0]s[0]是否等于'c'),仍然不匹配,那么就跳到ne[0]=−1n_e[0]=-1ne​[0]=−1,这个−1-1−1并不是一个真实状态,它是一个虚拟的状态,假想s[−1]s[-1]s[−1]是一个通配符,可以匹配任意字符,那么此时就匹配上了,沿着这条虚拟的边走到状态000(所以我们可以特判一下状态−1-1−1就行了,不需要真在程序里写这个状态);再比如,在状态111的时候读到了字符'b',那么此时是匹配的,直接沿着匹配边走到下一个状态,也就是状态222。
3、总结一下该DFA的跳转规则。当当前位于状态iii,并且读入了字符α\alphaα的时候,进行如下循环:只要当前处于的状态jjj不是−1-1−1,并且s[j]s[j]s[j]和α\alphaα不匹配,那么就跳转到ne[j]n_e[j]ne​[j]去,直到j=−1j=-1j=−1或者s[j]=αs[j]=\alphas[j]=α为止,此时沿着匹配边走一步到状态j+1j+1j+1去。总结来说就是δ(i,α)=j+1\delta(i,\alpha)=j+1δ(i,α)=j+1。

由于上述DFA接受某个字符串,当且仅当其以构造该DFA的模式串为子串。这样一来,要求不含SSS为子串的字符串数量,相当于就是在问,从DFA的状态000出发,跳转NNN次,并且中途和终点没有跳到接受状态lSl_SlS​的路径个数。这可以用动态规划来做。设f[k][p]f[k][p]f[k][p]是跳kkk步跳到状态ppp的路径条数,那么可以按照跳到状态ppp之前在哪儿来分类,则有:f[k][p]=∑q→pf[k−1][q]f[k][p]=\sum_{q\to p} f[k-1][q]f[k][p]=q→p∑​f[k−1][q]初始条件f[0][0]=1f[0][0]=1f[0][0]=1(因为初始状态就是状态000)。最终答案就是:∑p=0lS−1f[N][p]\sum_{p=0}^{l_S-1} f[N][p]p=0∑lS​−1​f[N][p]即跳NNN步没有跳到状态lSl_SlS​的路径条数。

由于不方便知道某个状态之前是哪个状态,我们可以用当前状态来更新未来状态,即可以用f[k−1][q]f[k-1][q]f[k−1][q]来累加到f[k][p]f[k][p]f[k][p]上去。代码如下:

#include <iostream>
#include <cstring>
using namespace std;const int N = 55, mod = 1e9 + 7;
int n, m;
char s[N];
int f[N][N];
int ne[N];// 求next数组
void build_ne() {ne[0] = -1;for (int i = 0, j = -1; i < m - 1;)if (j < 0 || s[j] == s[i]) {i++;j++;ne[i] = s[i] != s[j] ? j : ne[j];} else j = ne[j];
}int main() {scanf("%d%s", &n, s);m = strlen(s);build_ne();f[0][0] = 1;// 枚举步数for (int i = 1; i <= n; i++)// 枚举当前在哪个状态for (int j = 0; j < m; j++)// 枚举当前在状态j的时候获得的输入字符for (char ch = 'a'; ch <= 'z'; ch++) {// 开始计算从状态j开始,读入ch后会跳到哪个状态int u = j;while (u != -1 && ch != s[u]) u = ne[u];u++;// 状态s.size()是接受态,走到其的路径条数不用计算,否则累加一下路径条数if (u < m) f[i][u] = (f[i][u] + f[i - 1][j]) % mod;}int res = 0;for (int i = 0; i < m; i++) res = (res + f[n][i]) % mod;printf("%d\n", res);
}

时间复杂度O(NlS2)O(Nl_S^2)O(NlS2​),空间O(NlS)O(Nl_S)O(NlS​)。

下面给出字符串下标从111开始的版本。此版本中,设字符串长度mmm,那么状态是0,1,...,m0,1,...,m0,1,...,m这些,其中mmm是匹配状态,本题中不考虑。每个状态uuu在读入字符串ccc的时候,当c≠s[u+1]c\ne s[u+1]c​=s[u+1]的时候发生跳转,一直跳转到nek[u]ne^k[u]nek[u]直到u=0∨c=s[u+1]u=0\lor c= s[u+1]u=0∨c=s[u+1]成立,如果c=s[u+1]c=s[u+1]c=s[u+1]则uuu向后跳一格。代码如下:

#include <iostream>
#include <cstring>
using namespace std;const int N = 55, mod = 1e9 + 7;
int n, m;
char s[N];
int f[N][N], ne[N];void build_ne() {for (int i = 2, j = 0; i <= m; i++) {while (j && s[i] != s[j + 1]) j = ne[j];if (s[i] == s[j + 1]) j++;ne[i] = i < m && s[i + 1] != s[j + 1] ? j : ne[j];}
}int main() {cin >> n >> s + 1;m = strlen(s + 1);build_ne();f[0][0] = 1;for (int i = 0; i < n; i++)for (int j = 0; j < m; j++)for (char ch = 'a'; ch <= 'z'; ch++) {int u = j;while (u && s[u + 1] != ch) u = ne[u];if (s[u + 1] == ch) u++;if (u < m) f[i + 1][u] = (f[i + 1][u] + f[i][j]) % mod;}int res = 0;for (int j = 0; j < m; j++) res = (res + f[n][j]) % mod;printf("%d\n", res);
}

时空复杂度一样。

【ACWing】1052. 设计密码相关推荐

  1. 1052. 设计密码

    你现在需要设计一个密码 S,S 需要满足: S 的长度是 N: S 只包含小写英文字母: S 不包含子串 T: 例如:abc 和 abcde 是 abcde 的子串,abd 不是 abcde 的子串. ...

  2. 解锁秋天\秋季借势的海波设计密码!

    属于夏季的节气在热潮中离我们远去,一朝秋暮露成霜,荷败千池.白棉万顷.秋菊凌霜.芙蓉独芳.要说一种节气能让大自然都心生敬畏,那便是秋收冬藏的霜降时分.午后阳光不再灼热,于寒冷秋日,更显温暖.品尝一块满 ...

  3. 免费UI圆角字体素材|字体设计密码:字形设计中“圆角”的应用规范

    什么是圆角呢? 是指在字形制作过程为了给字形添加细节而用到的一个方法,在笔画相交或转折处.一般有内.外圆角两种. 外圆角 内圆角 给字形添加圆角虽然可以增加字形的精致感,但也不能随意添加,流于俗套不说 ...

  4. DP 状态机模型 AcWing算法提高课 详解

    状态机模型 AcWing 1049. 大盗阿福 #include <iostream> #include <algorithm> #include <cmath> ...

  5. acwing提高组 第一章 动态规划

    文章目录 数字三角形模型 最长上升子序列模型 背包模型 状态机模型 状态压缩DP 区间DP 树形DP 数位DP 单调队列优化DP 斜率优化DP oj链接 数字三角形模型 AcWing 1015. 摘花 ...

  6. Acwing算法—动态规划

    目录 数字三角形模型 AcWing 898. 数字三角形 AcWing 1015. 摘花生 AcWing 1018. 最低通行费 AcWing 1027. 方格取数 AcWing 275. 传纸条 最 ...

  7. 算法——AcWing算法提高课中代码和题解

    文章目录 第一章 动态规划 (完成情况:64/68) 数字三角形模型 最长上升子序列模型 背包模型 状态机模型 状态压缩DP 区间DP 树形DP 数位DP 单调队列优化DP 斜率优化DP 第二章 搜索 ...

  8. AcWing算法提高课

    1. 动态规划(43/68) 1.1 数字三角形模型(4/4) 1.1.1 AcWing 1015. 摘花生 结论: f[i][j]=max⁡(f[i−1][j],f[i][j−1])+w[i][j] ...

  9. 【动态规划】状态机模型

    整理的算法模板合集: ACM模板 文章目录 A.抛砖引玉 - AcWing 1049. 大盗阿福 B.AcWing 1057. 股票买卖 IV C.AcWing 1058. 股票买卖 V D.AcWi ...

最新文章

  1. 豆瓣评分9.3,陪伴无数程序员成长的神作,终于升级了!
  2. Application Loader:上传卡在App Store正在通过iTunes Store鉴定
  3. 史上最硬核的Linux依赖问题解决方案
  4. 从godaddy转出域名
  5. redis 源码 object.c 实现
  6. lan pci 联想开机_微软承认KB4568831导致部分联想ThinkPad笔记本崩溃和蓝屏
  7. MySQL 主从复制 复制过滤
  8. lamp怎么使用mysql_lamp(四)mysql操作
  9. 【TensorFlow-windows】(七) CNN之VGG-net的测试
  10. android 速度传感器,Android实战技巧之四十二:加速度传感器
  11. [转载收藏]三层式开发中的层次划分
  12. android开发 修改标题栏背景_Android哆啦A梦调试工具体验
  13. C++实现演讲比赛小项目
  14. 【UVALive - 7344】Numbered Cards【数位DP+状压DP】
  15. ps切图怎么做成html,PS切图怎么导出网页 PS切图怎么生成源代码
  16. jQuery TagsInput
  17. 我们为什么需要实时数据库?
  18. 即构推出微信引流方案,助力在线教育平台大幅降低获客成本
  19. python 股票交易接口 github_GitHub - Higgsbit/vnpy: 基于python的开源交易平台开发框架...
  20. Android高仿微信头像裁剪

热门文章

  1. Pytorch中retain_graph参数的作用
  2. FastDFS上传文件失败原因
  3. 大数据之Hive:greatest和least函数
  4. 升级High Sierra惊魂记
  5. 用Fragment实现图片简易浏览
  6. Win7系统怎么删除休眠文件?
  7. 使用SSH客户端远程登录Linux主机(可替代samba、ftp服务)
  8. textarea 属性placeholder
  9. 为什么用python扒取出来的数据为空列表_如何解决python xpath爬取页面得到空列表(语法都对的情况下)...
  10. 最懂区块链的十大女神,值得你关注 | 年度盘点