hz2016評測《==點 caioj.cn《==點
#include<map> #include<queue> #include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define Maxchar 1000000 #define Maxm 10000 #define Maxn 50 #define Maxs 26 #define mes(x,y) memset(x,y,sizeof(x)); #define mpy(x,y) memcpy(x,y,sizeof(x)) #define INF 2147483647 using namespace std; struct Tire{ int s,c[Maxs+1],fail; Tire(){ s=fail=0; mes(c,-1); } }t[Maxn*Maxm+1];//字典樹 int T,tot,ans,n; char a[Maxchar+1]; void clean(int x){ t[x].s=t[x].fail=0; for(int i=1;i<=Maxs;i++)t[x].c[i]=-1;//清空字典樹節點 } void bt(int root){ int x=root,len=strlen(a+1);//建字典樹 for(int i=1;i<=len;i++){//len個字符依次建節點 int y=a[i]-'a'+1;//把字符換成值 if(t[x].c[y]==-1){//如果沒有節點 t[x].c[y]=++tot;//給新的節點一個新編號 clean(tot);//先給他清空再給節點 } x=t[x].c[y];//我來新建的節點繼續建 } t[x].s++;//記錄下再節點這個位置結尾,就是這個字符串的結尾的位置是這個節點的個數,有點囉嗦,自己意會一下。 } queue<int> q; void bfs(){ q.push(0); while(q.empty()==0){//bfs循環找節點 int x=q.front(); for(int i=1;i<=Maxs;i++){ int son=t[x].c[i];//在樹上做kmp if(son==-1)continue;//找存在的節點 if(x==0)t[son].fail=0; else{ int j=t[x].fail; while(j!=0&&t[j].c[i]==-1)j=t[j].fail;//fail就是kmp的p數組然後一個一個跳 t[son].fail=max(t[j].c[i],0);//看看存不存在,不存在指向0,就是kmp的else p[i]=0; } q.push(son); } q.pop(); } } void solve(){ int x=0,len=strlen(a+1),j; for(int i=1;i<=len;i++){//在樹上查找 int y=a[i]-'a'+1; while(x!=0&&t[x].c[y]==-1)x=t[x].fail;//再找一下和這句話有沒有匹配的,有的話++ x=t[x].c[y]; if(x==-1){x=0;continue;} j=x; while(t[j].s!=0){ ans+=t[j].s;//s就是用來記錄有多少個符合的。 t[j].s=0; j=t[j].fail; } } printf("%d\n",ans); } int main(){ scanf("%d",&T); while(T--){ ans=tot=0; scanf("%d",&n); clean(0); for(int i=1;i<=n;i++){ scanf("%s",a+1); bt(0); } bfs(); scanf("%s",a+1); solve(); } return 0; }這題還是邊看代碼邊理解把,ac自動機是建立在Tire就是字典樹的基礎上,大家可以先去學一下字典樹,可惜暫時沒有字典樹的題。 就先練一下ac自動機吧,noip可能出的(某dalao:不出我當場吃屍米) 所以大家好好背模版。
查看原文:http://hz2016.tk/blog/?p=25