NOIP2017賽前模擬 字符串(AC自動機)

題意:
 給你n個單詞(字符串T)和一個文章(字符串S),q個詢問,每次修改S中的一個字符,然後輸出所有單詞在文章中的出現次數。一開始輸出沒有修改時的答案。

題解:
 先將每個單詞建一個AC自動機,在沒有修改時統計一個答案;
 然後我們發現,每次修改只會影響[pos-mx+1,pos+mx-1] (mx爲最長的單詞的長度,pos爲當前修改的位置)的答案,其餘多出的則不會影響;
 所以每次修改時我們只需要先將原來區間內的答案刪去,修改之後在將這段區間放到AC自動機上匹配,加上新的答案;
 另外還有注意普通的AC自動機在匹配時對於一個節點,會一直迭代,跳它的fail指針,統計答案,爲了避免超時,我們在一開始的時候就將一個節點所有fail指針跳的點的答案累加,後面匹配就不用迭代了

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<cstring>
#include<string>
#include<cctype>
using namespace std;
int ans,n,tot,qq,pos,mx,len;
int q[100010],tag[100010],fail[100010],f[100010][27];
char ch,s[200010];bool vis[100010];

inline void Insert(){
    int t=0;
    for(int i=1;i<=len;i++){
        if(!f[t][s[i]-'a']) f[t][s[i]-'a']=++tot;
        t=f[t][s[i]-'a'];
    }
    tag[t]++;
}

inline void getfail(){
    int head=0,tail=1,j;q[1]=0;
    while(head^tail){
        j=q[++head];
        if(j)
          for(int i=0;i<26;i++)
            if(f[j][i])
              fail[f[j][i]]=f[fail[j]][i];
          for(int i=0;i<26;i++)
            if(!f[j][i])
              f[j][i]=f[fail[j]][i];
            else q[++tail]=f[j][i];
    }
    for(int i=1;i<=tail;i++)
    {
        int u=q[i],v=fail[u];
        tag[u]+=tag[v];
    }
}


inline int ac(int st,int end){
    int now=0,tmp,ret=0;
    for(int i=st;i<=end;i++){
        now=f[now][s[i]-'a'];
        ret+=tag[now];
    }
    return ret;
}

int main(){
//  freopen("string.in","r",stdin);
    scanf("%d%d",&n,&qq);
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        len=strlen(s+1);
        mx=max(mx,len);
        Insert();
    }
    getfail();
    scanf("%s",s+1);len=strlen(s+1);
    ans=ac(1,len);
    cout<<ans<<endl;
    for(int i=1;i<=qq;i++){
        scanf("%d %c",&pos,&ch);
        int l=pos-mx+1,r=pos+mx-1;
        if(l<0) l=0; if(r>len) r=len;
        ans-=ac(l,r);s[pos]=ch;
        ans+=ac(l,r);
        cout<<ans<<endl;
    }
    return 0;
}

後記:
 由於這是我做的第三道AC自動機的題,所以模板不熟練,考試的時候就爆炸了,所以以後應該多做一些這樣的題

發佈了42 篇原創文章 · 獲贊 13 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章