hdu5716 hdu5745 shift-and字符串匹配
来源:互联网 发布:分卷包数据不正确修复 编辑:程序博客网 时间:2024/06/16 18:58
shift-and算法
2016大连regional的B题,字符串匹配,模板串每一位有若干种选择
一眼过去以为是KMP,写了之后一直超时,因为KMP会误配,使得不匹配的地方匹配,最后输出太多TLE
正解是shift-and,原来今年百度之星决赛和多校出过类似的题
hdu5716
题意:200W的文本串s是确定的,500的模板串t,每一位的字符在字符集当中,字符集最多包含大小写字母及数字,找出所有匹配点。
题解:n表示s的长度,m表示t的长度。dp[i][j]表示s[i-j+1..i]与t[1..j]是否相等
转移dp[i][j] = dp[i-1][j-1] && (s[i]∈t[j]),其中t[j]表示模板串第j位的字符集
这样复杂度是O(nm),考虑到i和j都是同步增加的,状态又是bool类型,可以用bitset优化
bitset优化有两种
方法1:dp[i]表示长度为n的bitset,dp[i][j]=1表示s到j这个位置和t匹配的长度可以为i
dp[i]=dp[i-1] << 1 & mt[t[i]]
mt[c]表示c这个字符可以和s的那些位置匹配
求mt[c]的复杂度是O(m∗size∗n64) ,size为字符集大小
方法2:dp[i]表示长度为m的bitset,dp[i][j]=1表示s以i结尾,和t匹配的长度可以为j
dp[i]=dp[i-1] << 1 & mt[s[i]]
mt[c]表示c这个字符可以和t的那些位置匹配
求mt[c]的复杂度是O(m∗size∗m64)
两种方法转移方程一样,dp的复杂度都是
O(n∗m64) ,但是mt的计算量不同,导致效率不一样。
字符集大小对复杂度影响也比较大
#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#include <bitset>using namespace std;const int M = 500+5;const int N = 2000000+5;const int SIZE = 64;const int MAGIC = 128;char txt[N];int id[MAGIC];bitset<M> dp[2];bitset<M> mt[MAGIC];int n, m;inline void output(bitset<M>& bt){ for (int i=0; i<=m; i++) printf("\t # %4d %4d\n", i, bt[i]?1:0); puts("");}int main(){ int cnt = 0; for (int i='0'; i<='9'; i++) id[i] = ++ cnt; for (int i='A'; i<='Z'; i++) id[i] = ++ cnt; for (int i='a'; i<='z'; i++) id[i] = ++ cnt; while (gets(txt+1)){ n = strlen(txt+1); scanf("%d", &m); int l; char s[SIZE]; for (int i=1; i<=cnt; i++) mt[i].reset(); for (int i=1; i<=m; i++){ scanf("%d %s", &l, s); for (int j=0; j<l; j++){ int x = id[s[j]]; mt[x].set(i); } } int cur = 0; dp[cur].reset(); dp[cur].set(0); bool flag = 0; for (int i=1; i<=n; i++){ int x = id[txt[i]]; cur ^= 1; dp[cur] = dp[cur^1] << 1 & mt[x]; dp[cur].set(0); if (dp[cur][m]){ flag = 1; printf("%d\n", i - m + 1); } } if (!flag) puts("NULL"); getchar(); } return 0;}
hdu5745
题意:10W的文本串s,5000的模板串t,其中t可以交换相邻的字符,但每个位置最多被交换一次,比如1和2交换,2和3就不能交换了,求出所有匹配点。
题解:类似上一题的做法,dp[i][j][0]表示s到i位置和t能否匹配j的长度,且j位置不能与后面交换(但可能跟前面交换,看作一种情况),dp[i][j][1]表示s到i位置和t能否匹配j的长度,且j位置与后面交换
转移方程为
dp[i][j][0] = (dp[i−1][j−1][1] &s[i]==t[j−1] ) | (dp[i−1][j−1][0] &s[i]==t[j] )
dp[i][j][1] = (dp[i−1][j−1][0] &s[i]==t[j+1] )
然后就是用bitset优化了,也是两种优化方式,预处理mt数组的复杂度也不一样
#include <cstdio>#include <cstring>#include <cstdlib>#include <algorithm>#include <bitset>using namespace std;const int N = 100000+10;const int M = 5000+5;const int SIZE = 26+2;const int MAGIC = 256;int n, m;char txt[N], pat[M];int s[N], t[M];bitset<N> dp[2][2];bitset<N> f[SIZE];bitset<N> ans;inline void output(bitset<N>& bt){ for (int i=1; i<=n; i++){ putchar(bt[i]?49:48); } putchar('\n');}int main(){ int test; scanf("%d", &test); while (test--){ scanf("%d %d", &n, &m); scanf("%s", txt+1); scanf("%s", pat+1); for (int i=1; i<=n; i++) s[i] = txt[i] - 'a'; for (int i=1; i<=m; i++) t[i] = pat[i] - 'a'; t[m+1] = 26; for (int i=0; i<SIZE; i++){ f[i].reset(); } for (int i=1; i<=n; i++) f[s[i]].set(i); int cur = 0, pre; dp[cur][0].set(); dp[cur][1].reset(); for (int i=1; i<=m; i++){ pre = cur; cur = pre ^ 1; dp[cur][0] = (dp[pre][1] << 1 & f[t[i-1]]) | (dp[pre][0] << 1 & f[t[i]]); dp[cur][1] = (dp[pre][0] << 1 & f[t[i+1]]); } ans = dp[cur][0] | dp[cur][1]; for (int i=1; i<=n; i++){ if (i+m-1<=n && ans[i+m-1]) putchar('1'); else putchar('0'); } putchar('\n'); } return 0;}
有意思的是上面的题需要用方法2,下面的题需要用方法1,不然tle
- hdu5716 hdu5745 shift-and字符串匹配
- hdu5745 字符串匹配 多校2.12
- 字符串匹配之Shift And算法
- 扩展字符串匹配-Shift-And算法扩展
- 字符串匹配算法-Shift And算法
- shift and与shift or字符串匹配算法
- [2016ACM多校] HDU5745 匹配
- HDU 5972 Regular Number Bitset (字符串匹配shift and/or)
- HDU 5972 Regular Number Bitset优化字符串匹配 +Shift-And算法
- hdu5716带可选字符的多字符串匹配
- 俩个模式匹配算法(BMH and shift-Or)
- 多字符串匹配-multiple shift-and算法
- hdu5745 La Vie en rose (字符串)
- Logical shift and Arithmetic shift
- shift-And / shift-Or 算法
- Flip and Shift(ZJU_1028)
- zoj1028 Flip and Shift
- pku1063 Flip and Shift
- 虚拟机能否上网的判断方法
- Tensorflow学习笔记(二)——MNIST机器学习入门
- 【Codewars-求矩阵行列式】python
- Mac与Phy组成原理的简单分析
- java in acm – 我所知道的一切
- hdu5716 hdu5745 shift-and字符串匹配
- MCU系统时钟
- Ubuntu系统下浏览器和终端的SS代理配置
- 【Basic Code】深拷贝、浅拷贝的代码实现(一)
- poj 3255 Roadblocks(次短路)
- Cocos2d-x ListView 的添加,删除,点击和滑动到头和尾监听
- 交换排序(快速排序 冒泡排序)
- 你不了解的Hacker,实现AngularJS Controller的继承扩展
- C++(继承篇)