HDU 5716 帶可選字符的多字符串匹配 (shift-and)

帶可選字符的多字符串匹配

Problem Description

有一個文本串,它的長度爲m(1≤m≤2000000),現在想找出其中所有的符合特定模式的子串位置。
符合特定模式是指,該子串的長度爲n(1≤n≤500),並且第i個字符需要在給定的字符集合Si中。
因此,描述這一特定模式,共需要S1,S2,…,Sn這n個字符集合。每個集合的大小都在1∼62之間,其中的字符只爲數字或大小寫字母。

Input

第一行爲一個字符串,表示待匹配的文本串。注意文本串中可能含有數字和大小寫字母之外的字符。
第二行爲一個整數n。
以下n行,分別描述n個字符集合。每行開始是一個1∼62之間的整數,隨後有一個空格,接下來有一個字符串表示對應字符集合的內容。整數表示字符集合的大小,因此它也就是字符串的長度。輸入保證字符串中的字符只爲數字或大小寫字母且沒有重複。(注:本題有多組測試數據)

Output

每當從某個位置開頭的,長度爲n的子串符合輸入的模式,就輸出一行,其中包含一個整數,爲它在文本串的起始位置。位置編號從1開始。
如果文本串沒有任何位置符合輸入模式,則最後輸出一個字符串”NULL”,佔一行。

Sample Input

aaaabacabcabd
3
3 abc
2 bc
3 abc

Sample Output

4
6
8
9


這應該是一道shift-and的模板題了。
注意到每個位置是一個字符集對shift-and並沒有影響,仍然只需要處理出文本串中每個字符在匹配串中出現位置,然後直接shift-and即可。

關於shift-and算法,用了一個數組F[i][j] ,F[i][j] 表示匹配串以j 結尾的前綴是否是文本串以i 結尾的前綴的後綴,簡單來說就是模式串以j 結尾能否匹配當前位置。

考慮轉移,F[i+1][j+1]=1 當且僅當F[i][j]=1 &&S[i+1]=T[j+1] ,令B[i] 表示字符i在串T 中出現位置的狀壓。那麼有F[i+1]=(F[i]<<1|1) &B[S[i+1]] ,利用bitset實現,可做到mn32 ,當匹配串較短時可認爲是線性。


代碼:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<bitset>
#define N 2000005
using namespace std;
char s[N],ss[N];
bitset<501>F,B[63];
int id(char t)
{
    if(t>='0'&&t<='9')return t-47;
    if(t>='A'&&t<='Z')return 11+t-'A';
    if(t>='a'&&t<='z')return 37+t-'a';
    return 0;
}
int main()
{
    int i,j,k,n;char c;bool f;
    while(gets(s+1))
    {
        int l=strlen(s+1);
        F.reset();f=0;
        for(i=0;i<63;i++)B[i].reset();
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&k);
            scanf("%s",&ss[1]);
            for(j=1;j<=k;j++)B[id(ss[j])][i]=1;
        }
        for(i=1;i<=l;i++)
        {
            F<<=1;F[1]=1;
            F&=B[id(s[i])];
            if(F[n]==1)printf("%d\n",i-n+1),f=1;
        }
        if(!f)puts("NULL");
        c=getchar();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章