Description
从前有一个迷宫,迷宫的外形就像一棵带根树,每个结点(除了叶子结点外)恰好有K个儿子。
一开始你在根结点,根结点的K个儿子分别标记为‘A’, ‘B’, ‘C’….,而结点‘A’的K个儿子结点分别标记为‘AA’,‘AB’,‘AC’……,依此类推。这棵树一共有L层。
现在你事先知道M个结点中有金子,并且你可以派出N个机器人去收集金子。首先你可以分别指定每一个机器人的目标结点,于是这些机器人就会收集从根结点到其目标结点这条路径上(包括目标结点)所有的金子,但是每个位置的金子只能被收集一次。
现在你需要制定一个目标的分配方案,使得收集到的金子最多。
Input
输入的第一行有4个整数:M,K,L,N。对应题目描述中的参数。
接下来M行,每行是一个字符串,表示所对应的结点上有金子。
Output
输出利用N个机器人所能捡到时最多几个结点上的金子。
Sample Input
样例1:
5 3 3 1
ACC
ACB
AB
AC
A
样例2:
5 3 3 2
ACC
ACB
AB
AC
A
Sample Output
样例输出1:
3
样例输出2:
4
Data Constraint
Hint
对于20%的数据有1<=M<=20.
对于40%的数据有1<=M<=2000.
对100%的数据,有
1<=M<=50000,1<=K<=26,1<=L<=50,1<=N<=50
分析:要取到一个字符串,可以把该字符串前缀全部取到。所以对于每个有金子字符串,向它的有金子的最长前缀连一条边。找前缀可以用排序后+hash或者字典树。
如:
S1=’AA’
S2=’AAA’
S3=’AAAB’
于是3向2连边,2向1连边,3不必向1连边。从而构成一个树的结构。
我们考虑树上统计答案,一个很显然的想法就是,设f[x,i]为到x节点,用了i个机器人的答案,有
f[x,i]=max(f[x,i],f[x,i-j],f[x.son,j])
复杂度为O(MN^2)
一开始以为会被卡,然后就过了= =
代码:
const
p=700007;
maxn=50001;
type
node=record
y,next:longint;
end;
re=record
s:string;
x:longint;
end;
var
n,m,k,l,x,e,i,j:longint;
hash:array [0..p] of re;
g:array [1..maxn*3] of node;
ls,a:array [0..maxn] of longint;
f:array [0..maxn,0..51] of longint;
v:array [0..maxn] of boolean;
s:array [0..maxn] of string;
flag:boolean;
function h(s:string):longint;
var i,pow,c:longint;
begin
pow:=1; c:=0;
for i:=1 to length(s) do
begin
c:=(c+pow*(ord(s[i])-ord('A'))) mod p;
pow:=(pow*26) mod p;
end;
exit(c);
end;
procedure ins(s:string;x:longint);
var i:longint;
begin
i:=h(s);
while hash[i].s<>'' do
i:=i mod p+1;
hash[i].s:=s;
hash[i].x:=x;
end;
function find(s:string):longint;
var i:longint;
begin
i:=h(s);
while hash[i].s<>'' do
begin
if hash[i].s=s then exit(hash[i].x);
i:=i mod p+1;
end;
exit(0);
end;
procedure add(x,y:longint);
begin
inc(e);
g[e].y:=y;
g[e].next:=ls[x];
ls[x]:=e;
end;
function max(x,y:longint):longint;
begin
if x>y then exit(x)
else exit(y);
end;
procedure qsort(l,r:longint);
var
i,j:longint;
key,temp:string;
begin
if l>=r then exit;
i:=l;j:=r;
key:=s[l+random(r-l+1)];
repeat
while (s[i]<key) do inc(i);
while (s[j]>key) do dec(j);
if i<=j then
begin
temp:=s[i];s[i]:=s[j];s[j]:=temp;
inc(i);dec(j);
end;
until i>j;
qsort(l,j);
qsort(i,r);
end;
procedure dfs(x:longint);
var t,i,j:longint;
begin
f[x,0]:=0;
t:=ls[x];
while t>0 do
with g[t] do
begin
if v[y]=false then
begin
v[y]:=true;
dfs(y);
for i:=n downto 1 do
for j:=0 to i do
f[x,i]:=max(f[x,i],f[x,i-j]+f[y,j]);
end;
t:=next;
end;
for i:=1 to n do
f[x,i]:=f[x,i]+a[x];
end;
begin
readln(m,k,l,n);
for i:=1 to m do
readln(s[i]);
qsort(1,m);
for i:=1 to m do
begin
flag:=false;
for j:=length(s[i]) downto 1 do
begin
x:=find(copy(s[i],1,j));
if x<>0 then
begin
flag:=true;
if j=length(s[i]) then inc(a[x])
else
begin
add(x,i);
add(i,x);
ins(s[i],i);
a[i]:=1;
end;
break;
end;
end;
if flag=false then begin add(0,i); ins(s[i],i); a[i]:=1; end;
end;
v[0]:=true;
dfs(0);
writeln(f[0,n]);
end.