$shift-and$算法,大致就是设$v[i][j]$表示读到文本串的$s[i-j+1]~s[i]$是否出现在相应集合中,
$f[i][j]$表示第$j$个集合中是否有字符$i$,那么有$$v[i+1][j+1]=v[i][j]且f[s[i+1]][j+1]$$
显然$j$这一维可以用$bitset$加速,时间复杂度$O(\frac{nm}{64})$。
关于此算法,推荐一篇文章:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #include<bits/stdc++.h> #define FILE "read" #define MAXN 2000010 using namespace std; typedef bitset<550> Int; int n,m,CantCount; char str[MAXN],ch[550]; Int f[105],v; inline int read(){ int x=0,f=1; char ch=getchar(); while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } int get(char ch){ if(ch>='0'&&ch<='9') return ch-'0'+1; else if(ch>='a'&&ch<='z') return ch-'a'+11; else if(ch>='A'&&ch<='Z') return ch-'A'+37; else return 0; } void solve(){ n=strlen(str+1); m=read(); CantCount=1; v.reset(); for(int i=1;i<=100;++i) f[i].reset(); for(int i=1;i<=m;++i){ int len=read(); scanf("%s",ch+1); for(int j=1;j<=len;++j) f[get(ch[j])][i]=1; } for(int i=1;i<=n;++i){ v=(v<<1)&f[get(str[i])]; v[1]=f[get(str[i])][1]; if(v[m]) printf("%d\n",i-m+1),CantCount=0; } if(CantCount) puts("NULL"); getchar(); } int main(){ freopen(FILE".in","r",stdin); freopen(FILE".out","w",stdout); while(gets(str+1)) solve(); return 0; }
|