题解 P2580 【于是他错误的点名开始了】
ljc20020730 · · 题解
标解为字典树,水题……
裸的字典树,但是用指针实现
应该不能直接开二维数组容易挂MLE
题目说每行一个字符串表示其名字(互不相同,且只含小写字母,长度不超过 50),直接想到字典树
弄个指针中间的record为如下2个
type
node=^rec;
rec=record
next:array[1..26]of node;//下一层的26字母
vis:boolean;//有无被访问
end;
至于是否记录是否为单词结束,就无关紧要了 每次成功找到名字就把p^.vis=false(初始为true);
如果当前层的某一个字母找不到了(p^.next[w]=nil) 那么就判定为无学生名字exit
注意在每次新建指针前先new一下,否则爆216(据说是因为访问无效内存?!)
除了指针恶心点,其他都还好
恩,接下来讲讲暴力:
快排(n log n); 二分查找(m log n);
弄点**维护一下是否找过该名字(二叉排序树)应该也能在m log n内完成;
所以暴力时间复杂度O(m log n);
BUT,容易卡内存……
而字典树,巧妙的利用有些单词的前缀可能一样的来简化空间复杂度(特别加了指针)
时间也是比较快速O(k)查询O(k)建立【k为常数基本为O(1)】(和层数有关,由于名字长度不超过 50,所以常数k最大为50)
pascal代码如下:
const maxn=10000;
type
node=^rec;
rec=record
next:array[1..26]of node;
vis:boolean;
end;
var root:node;
s:string;
n,m,p,i:longint;
procedure insert(s:string);
var p,newnode:node;
w,i,j:longint;
begin
p:=root;
for i:=1 to length(s) do begin
w:=ord(s[i])-96;
if p^.next[w]=nil then begin
new(newnode);
for j:=1 to 26 do newnode^.next[j]:=nil;
p^.next[w]:=newnode;
p:=newnode;
end else p:=p^.next[w];
end;
p^.vis:=true;
end;
function find(s:string):longint;
var p:node;
i,w:longint;
begin
p:=root;
for i:=1 to length(s) do begin
w:=ord(s[i])-96;
if (p^.next[w]=nil) then exit(3);
p:=p^.next[w];
end;
if p^.vis=false then exit(2)
else begin p^.vis:=false; exit(1); end;
end;
begin
new(root);
for i:=1 to 26 do root^.next[i]:=nil;
root^.vis:=false;
readln(n);
for i:=1 to n do begin
readln(s);
insert(s);
end;
readln(m);
for i:=1 to m do begin
readln(s);
p:=find(s);
case p of
1:begin writeln('OK');end;
2:begin writeln('REPEAT');end;
3:begin writeln('WRONG');end;
end;
end;
end.