shift-and 算法初体验
shift-and算法的思想与kmp的算法思想类似,更简单
shift-and算法的适用范围是字符串匹配,但是此时模板串可以有很多个
题意:模式串有n位长度,n的大小是1000,每一位有x种选择,x的大小是10,也就是说模式串组合的话,大约可以组合出来10^1000种,于是普通的AC自动机什么的都GG了
shift-and是用bitset实现的,bitset是高端卡常题的宠儿,很少被我使用的经典STL
bitset可以想象成是vector容器,对于每一位只占用一个字节,也就是char型的八分之一的大小,于是省时又省空间
需要注意的是:假设声明bitset<int>foo; 那么foo[0]会显示在最右端,foo[n-1]会显示在最左端,刚好与普通的数组是相反的
foo.set() 全部设置为1
foo.reset() 全部设置为0
foo.set(x) 将foo[x]设置成1
foo.reset(x) 将foo[x]设置成0
按照代码理解吧~
首先是输入部分
build() 函数的作用是构建bitset , solve() 函数就是解决问题 具体怎么实习的后面介绍
首先我声明的bitset长度就是n的大小,10个bitset,记录的就是每一个数字可以出现在第几位
接下来ans也是一个bitset,他记录我们在处理过程中的结果
每一步 我们就将当前位直接置1,询问这一位是否可以匹配,与前面的,当前面也可以,这一步也可以的话,那么这一个就匹配成功
代码如下:
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> #include<vector> #include<bitset> using namespace std; const int maxn = 1003; int n , x , num; vector<int>V[maxn]; char s[5000006]; bitset<maxn>b[13] , ans; void build() { for(int i=0; i<10; i++) { b[i].reset(); } ans.reset(); for(int i=0; i<n; i++) { for(int j=0; j<V[i].size(); j++) { b[V[i][j]].set(i); } } // for(int i=0; i<10; i++) // { // cout<<b[i]<<endl; // } } void solve() { int len = strlen(s); for(int i=0; i<len; i++) { int tmp = s[i]-'0'; ans = ans<<1; ans.set(0); ans = ans&b[tmp]; if(ans[n-1]==1) { char ttmp = s[i+1]; s[i+1] = '\0'; puts(s+i+1-n); s[i+1] = ttmp; } } } void init() { for(int i=0; i<n; i++) { V[i].clear(); } } int main() { while( scanf("%d" , &n) != EOF ) { init(); for(int i=0; i<n; i++) { scanf("%d" , &x); for(int j=1; j<=x; j++) { scanf("%d" , &num); V[i].push_back(num); } } scanf("%s" , s); build(); solve(); } return 0; }