这里学习AC自动机
其实对KMP和trie掌握好了之后很容易扩展成AC自动机的
这里运用了一个性质
由失配指针反向可以建成一棵fail树
x串在y串中的出现的次数即为在fail树上以x结尾节点为根的子树中有多少个节点属于y串,这很好理解
而推广到这题,在文章中出现的次数即为单词结尾节点为根的子树的规模
注意这道题有相同的单词
当初这题我是用后缀数组做的O(LlogL)
而自动机复杂度为O(L),快了很多

 1 type node=record
 2        po,next:longint;
 3      end;
 4 
 5 var e:array[0..1000010] of node;
 6     trie:array[0..1000010,'a'..'z'] of longint;
 7     q,f,p,w:array[0..1000010] of longint;
 8     v:array[0..210] of longint;
 9     t,i,j,k,n,l,len:longint;
10     s:ansistring;
11 
12 procedure add(x,y:longint);
13   begin
14     inc(len);
15     e[len].po:=y;
16     e[len].next:=p[x];
17     p[x]:=len;
18   end;
19 
20 procedure bfs;
21   var x,y,h,r,j:longint;
22       c:char;
23   begin
24     h:=1;
25     r:=0;
26     for c:='a' to 'z' do
27       if trie[0,c]>0 then
28       begin
29         add(0,trie[0,c]);
30         inc(r);
31         q[r]:=trie[0,c];
32       end;
33 
34     while h<=r do
35     begin
36       x:=q[h];
37       for c:='a' to 'z' do
38         if trie[x,c]>0 then
39         begin
40           y:=trie[x,c];
41           inc(r);
42           q[r]:=y;
43           j:=f[x];
44           while (j>0) and (trie[j,c]=0) do j:=f[j];
45           f[y]:=trie[j,c];
46           add(trie[j,c],y);
47         end;
48       inc(h);
49     end;
50   end;
51 
52 procedure dfs(x:longint);
53   var i,y:longint;
54   begin
55     i:=p[x];
56     while i<>0 do
57     begin
58       y:=e[i].po;
59       dfs(y);
60       w[x]:=w[y]+w[x];
61       i:=e[i].next;
62     end;
63   end;
64 
65 begin
66   readln(n);
67   for i:=1 to n do
68   begin
69     readln(s);
70     j:=0;
71     l:=length(s);
72     for k:=1 to l do
73     begin
74       if trie[j,s[k]]=0 then
75       begin
76         inc(t);
77         trie[j,s[k]]:=t;
78       end;
79       j:=trie[j,s[k]];
80       inc(w[j]);
81     end;
82     v[i]:=j;
83   end;
84   bfs;
85   dfs(0);
86   for i:=1 to n do
87     writeln(w[v[i]]);
88 end.
ac自动机
  1 var h,rank,x,y,sum,sa:array[0..1010000] of longint;
  2     f:array[0..1010000,0..30] of longint;
  3     where,len,d:array[0..500] of longint;
  4     now, k,ans,i,j,p,n,m,t,l,r:longint;
  5     s,cc:ansistring;
  6 function min(a,b:longint):longint;
  7   begin
  8     if a>b then exit(b) else exit(a);
  9   end;
 10 
 11 function lcp(a,b:longint):longint;
 12   var k:longint;
 13   begin
 14     k:=trunc(ln(b-a+1)/ln(2));
 15     exit(min(f[a,k],f[b-d[k]+1,k]));
 16   end;
 17 
 18 begin
 19   readln(t);
 20   for i:=1 to t do
 21   begin
 22     readln(cc);
 23     where[i]:=length(s)+1;
 24     len[i]:=length(cc);
 25     s:=s+cc;
 26     if i<>t then s:=s+' ';
 27   end;
 28 {  for i:=1 to t do
 29      writeln(where[i],' ',len[i]);}
 30   n:=length(s);
 31   for i:=1 to n do
 32   begin
 33     y[i]:=ord(s[i]);
 34     inc(sum[y[i]]);
 35   end;
 36   m:=130;
 37   for i:=2 to 130 do
 38     inc(sum[i],sum[i-1]);
 39   for i:=1 to n do
 40   begin
 41     sa[sum[y[i]]]:=i;
 42     dec(sum[y[i]]);
 43   end;
 44   p:=1;
 45   rank[sa[1]]:=1;
 46   for i:=2 to n do
 47   begin
 48     if y[sa[i]]<>y[sa[i-1]] then inc(p);
 49     rank[sa[i]]:=p;
 50   end;
 51   m:=p;
 52   j:=1;
 53   while m<n do
 54   begin
 55     y:=rank;
 56     fillchar(sum,sizeof(sum),0);
 57     p:=0;
 58     for i:=n-j+1 to n do
 59     begin
 60       inc(p);
 61       x[p]:=i;
 62     end;
 63     for i:=1 to n do
 64       if sa[i]>j then
 65       begin
 66         inc(p);
 67         x[p]:=sa[i]-j;
 68       end;
 69     for i:=1 to n do
 70     begin
 71       rank[i]:=y[x[i]];
 72       inc(sum[rank[i]]);
 73     end;
 74     for i:=2 to m do
 75       inc(sum[i],sum[i-1]);
 76     for i:=n downto 1 do
 77     begin
 78       sa[sum[rank[i]]]:=x[i];
 79       dec(sum[rank[i]]);
 80     end;
 81     p:=1;
 82     rank[sa[1]]:=1;
 83     for i:=2 to n do
 84     begin
 85       if (y[sa[i]]<>y[sa[i-1]]) or (y[sa[i]+j]<>y[sa[i-1]+j]) then inc(p);
 86       rank[sa[i]]:=p;
 87     end;
 88     j:=j shl 1;
 89     m:=p;
 90   end;
 91   h[1]:=0;
 92   p:=0;
 93   for i:=1 to n do
 94   begin
 95     if rank[i]=1 then continue;
 96     j:=sa[rank[i]-1];
 97     while s[i+p]=s[j+p] do inc(p);
 98     h[rank[i]]:=p;
 99     if p>0 then dec(p);
100   end;
101   k:=trunc(ln(n)/ln(2));
102   d[0]:=1;
103   for i:=1 to k do
104     d[i]:=d[i-1]*2;
105   for i:=1 to n do
106     f[i,0]:=h[i];
107   for j:=1 to k do
108     for i:=1 to n do
109       if i+d[j]-1<=n then
110       begin
111         f[i,j]:=min(f[i,j-1],f[i+d[j-1],j-1]);
112       end
113       else break;
114   for i:=1 to t do
115   begin
116     ans:=1;
117     k:=-1;
118     l:=1;
119     now:=rank[where[i]];
120     r:=now-1;
121     while l<=r do
122     begin
123       m:=(l+r) shr 1;
124       if lcp(m+1,now)>=len[i] then
125       begin
126         k:=m;
127         r:=m-1
128       end
129       else l:=m+1;
130     end;
131     if k<>-1 then ans:=ans+now-k;
132     l:=now+1;
133     k:=-1;
134     r:=n;
135     while l<=r do
136     begin
137       m:=(l+r) shr 1;
138       if lcp(now+1,m)>=len[i] then
139       begin
140         k:=m;
141         l:=m+1;
142       end
143       else r:=m-1;
144     end;
145     if k<>-1 then ans:=ans+k-now;
146     writeln(ans);
147   end;
148 end.
后缀数组

 

posted on 2015-02-07 10:50  acphile  阅读(159)  评论(0编辑  收藏  举报