【NOIP2018复习】字典(字典树)

Description

Input

第一行两个数n,m,表示有n个字符串,m个询问。
接下来n行,每行一个字符串Ti 。
再接下来m行,每行一个字符串Si 。

Output

对于每个询问,输出一个ansi表示答案。

Sample Input

3 2
abcabc
aabc
abbc
aa
ba  

Sample Output

1
3 

题解:看到前缀和只有abc,想到字典树

            先对原始的字符串建立Trie,对Trie上每一个点建立形如(1,0,0,1)的数组,记录第i个原始串是否能匹配。在匹配模式串的时候就可以很容易得到答案。但是这么做会炸内存。

进一步思考可以发现,对于每个点上类似于(1,0,0,1,0,1)的数组,相邻的两个1对后续没有影响。因此在建树时,我们用一个ans数组记录 以第i个点为结尾的模式串 的答案。对于ans[i],当有模式串匹配到i点时,ans[i]=max(ans[i],time-last[i]-1) ,time指当前原始串的序号,last[i]指上一个匹配到该位置的原始串序号,即(1,0,0,1,0,1)中两个1的间隔。 

            注意:每个字符串的最后一个位置一直到n也是一个合法区间,不能遗漏,最终输出时比较max(ans[x],n-last[x])

const
  maxn=100000;
  maxm=5000000;
  inf='word.in';
  ouf='word.out';
var
  ans,last:array[0..maxm]of longint;
  trie:array[0..maxm,'a'..'c']of longint;

  st:array[0..maxm]of char;
  n,m,sum,len,i,j,flag:longint;
  s:ansistring;

{procedure add(x,y:longint);
begin
  inc(e[0]);
  e[e[0]]:=y;
  next[e[0]]:=last[x];
  last[x]:=e[0];
end;   }

function max(a,b:longint):longint;
begin
  if a>b then exit(a)  else exit(b);
end;

procedure build(st:ansistring;time:longint);
var
  i,head,tail,flag,x:longint;
  ch:char;
begin
  x:=0;
  for i:=1 to len do
  begin
    if trie[x,st[i]]=0 then
    begin
      inc(sum);
      trie[x,st[i]]:=sum;
      x:=sum;
      ans[x]:=max(ans[x],time-last[x]-1);
      last[x]:=time;

      continue;
    end;
    x:=trie[x,st[i]];
    ans[x]:=max(time-last[x]-1,ans[x]);
    last[x]:=time;
  end;
end;

procedure init;
var
  i,j,sum:longint;
  s:ansistring;
begin
  readln(n,m);
  for i:=1 to n do
  begin
    readln(s);
    len:=length(s);
    build(s,i);
  end;

end;

function find(st:ansistring):longint;
var
  x,i:longint;
begin
  x:=0;
  for i:=1 to len do
  begin
    if trie[x,st[i]]=0 then exit(n);
    x:=trie[x,st[i]];
  end;
  exit(max(ans[x],n-last[x]));
end;

begin
  assign(input,inf);reset(input);
  assign(output,ouf);rewrite(output);
  init;
  for i:=1 to m do
  begin
    readln(s);
    len:=length(s);
    writeln(find(s));
  end;
  close(input);close(output);
end.

 

知识点(by chs): 1、 一个32位整型变量占4字节(一个字节8位) 2、 运算符优先级表 !> & > ^ > | > && > || 常用:除、乘、取余、加、减。(按优先级从大到小顺序) 优先级 运算符 名称或含义 使用形式 结合方向 说明 1 [] 数组下标 数组名[常量表达式] 左到右 () 圆括号 (表达式)/函数名(形参表) . 成员选择(对象) 对象.成员名 -> 成员选择(指针) 对象指针->成员名 2 - 负号运算符 -常量 右到左 单目运算符 (type) 强制类型转换 (数据类型)表达式 ++ 自增运算符 ++变量名 单目运算符 -- 自减运算符 --变量名 单目运算符 * 取值运算符 *指针变量 单目运算符 & 取地址运算符 &变量名 单目运算符 ! 逻辑非运算符 !表达式 单目运算符 ~ 按位取反运算符 ~表达式 单目运算符 Sizeof 长度运算符 sizeof(表达式) 3 / 除 表达式/表达式 左到右 双目运算符 * 乘 表达式*表达式 双目运算符 % 余数(取模) 整型表达式%整型表达式 双目运算符 4 + 加 表达式+表达式 左到右 双目运算符 - 减 表达式-表达式 双目运算符 5 << 左移 变量<<表达式 左到右 双目运算符 >> 右移 变量>>表达式 双目运算符 6 > 大于 表达式>表达式 左到右 双目运算符 >= 大于等于 表达式>=表达式 双目运算符 < 小于 表达式<表达式 双目运算符 <= 小于等于 表达式<=表达式 双目运算符 7 == 等于 表达式==表达式 左到右 双目运算符 != 不等于 表达式!= 表达式 双目运算符 8 & 按位与 表达式&表达式 左到右 双目运算符 9 ^ 按位异或 表达式^表达式 左到右 双目运算符 10 | 按位或 表达式|表达式 左到右 双目运算符 11 && 逻辑与 表达式&&表达式 左到右 双目运算符 12 || 逻辑或 表达式||表达式 左到右 双目运算符 13 ?: 条件运算符 表达式1? 表达式2: 表达式3 右到左 三目运算符 14 = 赋值运算符 变量=表达式 右到左 /= 除后赋值 变量/=表达式 *= 乘后赋值 变量*=表达式 %= 取模后赋值 变量%=表达式 += 加后赋值 变量+=表达式 -= 减后赋值 变量-=表达式 <<= 左移后赋值 变量<<=表达式 >>= 右移后赋值 变量>>=表达式 &= 按位与后赋值 变量&=表达式 ^= 按位异或后赋值 变量^=表达式 |= 按位或后赋值 变量|=表达式 15 , 逗号运算符 表达式,表达式,… 左到右 从左向右顺序运算 3、 完全图及其性质:若一个图的每一对不同顶点恰有一条边相连,则称为完全图。完全图是每对顶点之间都恰连有一条边的简单图。n个端点的完全图有n个端点及n(n − 1) / 2条边 4、 冒泡排序!!!归并排序!!!(注意相同的数排序后的不同位置)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值