[AC自动机][fail树][BZOJ 3172][TJOI2013]单词

本文介绍了一种使用AC自动机解决论文中单词重复计数的问题,通过构建AC自动机并进行DFS遍历来计算每个单词在论文中出现的次数。文中详细解释了AC自动机的构建过程及其实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。每个单词由小写字母组成,N<=200,单词总长度不超过10^6。

Analysis
建出AC自动机,然后对于一个点i和它的Fail[i]反向连边。这样构造出来的是一个树。
对于一个单词它出现的次数就是这个单词的结尾节点X的子树大小。证明是容易的。
不过这里的子树大小指的是每一个节点被访问过的次数和...
上代码:
var
  b:array[1..1000000,'a'..'z'] of longint;
  ch:char;
  i,edge,sum,n,k:longint;
  fa,s,next,d,fr:array[1..1000000] of longint;
  c:array[1..1000000] of char;
  word:array[1..200] of longint;
  e:array[1..1000000,1..2] of longint;
procedure build_trie;
var
  now,i:longint;
begin
  sum:=1;
  for i:=1 to n do begin
    now:=1;
    repeat
      read(ch);
      if b[now,ch]=0 then begin
        inc(sum);
        b[now,ch]:=sum;
        c[sum]:=ch;
        fa[sum]:=now;
        now:=sum;
      end
      else now:=b[now,ch];
      inc(s[now]);
    until eoln;
    word[i]:=now;
    readln;
  end;
end;
procedure add(x,y:longint);
begin
  inc(edge); e[edge,1]:=y; e[edge,2]:=fr[x]; fr[x]:=edge;
end;
function get_next(x:longint):longint;
begin
  if (b[x,c[k]]<>0) and (b[x,c[k]]<>k)  then exit(b[x,c[k]]);
  if x=1 then exit(1) else get_next:=get_next(next[x]);
end;
procedure build_ac;
var
  h,t,i:longint;
begin
  h:=0; t:=1; d[t]:=1; next[1]:=1;
  repeat
    inc(h);
    k:=d[h];
    if k<>1 then next[k]:=get_next(fa[k]);
    for ch:='a' to 'z' do
      if b[k,ch]<>0 then begin inc(t); d[t]:=b[k,ch]; end;
  until h=t;
  for i:=2 to sum do add(next[i],i);
end;
procedure dfs(x:longint);
var
  k:longint;
begin
  k:=fr[x];
  while k<>0 do begin
    dfs(e[k,1]);
    s[x]:=s[x]+s[e[k,1]];
    k:=e[k,2];
  end;
end;
begin
  readln(n);
  build_trie;
  build_ac;
  dfs(1);
  for i:=1 to n do writeln(s[word[i]]);
end.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值