字符串练习
来源:互联网 发布:网络校时软件 编辑:程序博客网 时间:2024/06/06 05:18
快要区域赛了,恶补ing。
先复习一下学习过的字符串知识吧。
由于本人是弱渣,先来几个板子题磨练一下板子。
先来复习一下模式匹配的知识,写两个ac自动机。
HDU2222 Keywords Search
给多个模板串,进行匹配。
模板题。沿着trie树走,然后要沿着fail边跳,来统计。
POJ 2776
给一些禁止的串,然后问长度为n的没有禁止的串的串的个数。
在禁止的串构成的ac自动机上游走,然后可以转移,研究研究发现可以用矩阵加速。
板子新鲜出炉。
struct Ac{ int ch[maxn * 50][26]; int fail[maxn * 50]; int val[maxn * 50]; int q[maxn * 50]; int tot; Ac(){} int id(char c){ return c - 'a'; } void init(){ tot = 0; fail[0] = -1;memset(ch,0,sizeof(ch));val[0] = 0; } void insert(char *s,int len){ int now = 0; for(int i = 0;i < len;i++){ int tr = id(s[i]); if(ch[now][tr] == 0){ ch[now][tr] = ++tot; memset(ch[tot],0,sizeof(ch[tot])); val[tot] = 0; fail[tot] = 0; } now = ch[now][tr]; } val[now]++; } void make(){ int h = 1,t = 0; for(int i = 0;i < 26;i++) if(ch[0][i] != 0) q[++t] = ch[0][i]; while(h <= t){ int now = q[h++]; for(int i = 0;i < 26;i++){ if(ch[now][i] == 0){ ch[now][i] = ch[fail[now]][i]; }else{ fail[ch[now][i]] = ch[fail[now]][i]; q[++t] = ch[now][i]; } } } } int search(char *s,int len){ //不可思议的操作 }}ac;
后缀自动机
SPOJ694
求一个串本质不同的子串个数。sa和sam都可以做。先用sam来a一下。sdoi2016的生成魔咒还复杂一点,但都是模板题。
我的板子。
struct Sam{ int fail[maxn * 2]; int ch[maxn * 2][256];int tot,last; int mx[maxn * 2]; int ans; void clear(int i){ memset(ch[i],0,sizeof(ch[i])); } void clear(){ tot = last = 1; ans = 0; clear(0);clear(1); } Sam(){ tot = last = 1; ans = 0; clear(0);clear(1); } int cal(int x){ return mx[x] - mx[fail[x]]; } void add(int c){ int p = last,np = last = ++tot;clear(tot); mx[np] = mx[p] + 1; while(p && ch[p][c] == 0) ch[p][c] = np,p = fail[p]; if(!p) fail[np] = 1,ans += cal(np); else{ int q = ch[p][c]; if(mx[q] == mx[p] + 1) fail[np] = q,ans += cal(np); else{ int nq = ++tot;clear(tot);mx[nq] = mx[p] + 1; memcpy(ch[nq],ch[q],sizeof(ch[nq])); fail[nq] = fail[q];ans+=cal(nq)-cal(q); fail[q] = fail[np] = nq;ans+=cal(np)+cal(q); while(p && ch[p][c] == q) ch[p][c] = nq,p = fail[p]; } } }}sam;
扩展kmp
普通的kmp是计算以i为结尾的串和前缀的最大重叠,这个是计算以i为开头的,理解了一下,感觉原理差不大多,都借用了一些前面的状态。然后细节稍微复杂一点。
抄了个板子。
//字符串以0开始void get_next(){ nex[0] = N; int p = 0; while (p < N && B[p] == B[p + 1]) p ++; nex[1] = p; int k = 1, L; for (int i = 2; i < N; i ++) { p = k + nex[k] - 1; L = nex[i - k]; if (i + L <= p) { nex[i] = L; } else { int j = max(p - i + 1, 0); while (i + j < N && B[i + j] == B[j]) j ++; nex[i] = j; k = i; } }}void get_extend(){ int p = 0; while (p < N && A[p] == B[p]) p ++; extend[0] = p; int k = 0, L; for (int i = 1; i < N; i ++) { p = k + extend[k] - 1; L = nex[i - k]; if (i + L <= p) { extend[i] = L; } else { int j = max(p - i + 1, 0); while (i + j < N && A[i + j] == B[j]) j ++; extend[i] = j; k = i; } }}
然后讲个例题吧。
比如长沙理工大学2017校赛的H。
题意:大概就是给你一个数,让你从中间拆开成a,b两个数,然后计算a + b后面最多几个0
这题很明显要kmp,但是当场做的时候不知道拓展kmp,然后XJB摸鱼写二分 + kmp,我很傻逼啊。
然后正解是这样的,因为我们肯定要考虑进位嘛,所以要从低位开始考虑,然后先把串反转,然后计算一下补串。然后做一下扩展kmp。同时我们维护两个数组,一个是从i位置开始的连续的0有多少个,还有一个是从i位置开始的连续的9有多少个。
那么我们假设考虑原串的i位置,假设它的extend是j,那么由于不能重叠,所以l = min(i,j),这个时候我们要看两个情况,如果l == i,就是从i位置断开,那么我们要看i + l处有多少个连续的0或者9(不同的情况),然后看前i位是不是全0,如果全0就要看连续0,如果不是那么可以进位,就看连续的9。还有是如果i + l = 串长的时候要看l位置开始的连续的0或者9。
这边可以提交。
https://www.nowcoder.com/acm/contest/1#question
shift-and算法。
感觉这就是个用bitset优化的暴力啊哈???
例题
广西邀请赛17J,16年大连B。
- 字符串练习
- 字符串 练习
- 字符串练习
- 字符串练习
- 字符串练习
- 字符串练习
- 字符串练习
- 字符串练习
- 字符串练习
- 字符串练习
- 字符串练习
- 字符串练习
- 字符串练习
- 字符串练习
- [字符串]HDU1106 字符串相关练习
- 字符串编程练习
- 字符串练习的源代码
- 字符串处理练习
- Sql 中存储过程详细案例
- centos 查找文件
- enum枚举类型的使用(上)
- 数据库
- (web服务器)到嵌入式Linux系统
- 字符串练习
- bower的安装和使用
- TensorFlow 变量共享,命名空间
- JAVA-初步认识-第二章-自动类型提升&强制类型转换
- 51nod1241[特殊的排序]【贪心】
- ip地址错误解决方法
- opencv训练样本
- 深度学习(三)---卷积神经网络
- 欢迎使用CSDN-markdown编辑器