zoukankan      html  css  js  c++  java
  • bzoj3172

    这里学习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.
    后缀数组
  • 相关阅读:
    修改MySQL表中自增编号
    springboot整合mybatis统一配置bean的别名
    kotlin来了!!
    微信小程序获取登录手机号
    maven--package
    修改oracle数据库时间
    oracle启动停止命令
    安装 MySQL 之后初始密码在哪里??
    EntityFramework~~~三种模式
    webqq协议分析之~~~~验证是否需要验证码
  • 原文地址:https://www.cnblogs.com/phile/p/4473000.html
Copyright © 2011-2022 走看看