Description
经过一番周折,Bob找到了Alice,为了安慰Alice惊魂未定的心,Bob决定给Alice买一条手链,这条手链由M个珍珠组成,每个珍珠上刻着不同的小写字母。当Alice看到一些字母按照一定的顺序排列成的字符串时,就会产生一定的愉悦值。Bob现在可以在这M个珍珠上刻上字母,现在他想知道,如何刻字母可以使得Alice的愉悦值最大。
Input
第一个行两个数N和M,分别表示GF喜欢的字符串的个数和项链长度。
第二行N个数,Ai表示第i的字符串带给GF的愉悦值
接下来N行每行一个字符串,表示GF喜欢的字符串
Output
一行,一个数,表示最大愉悦值。
Sample Input
输入1:
3 6
3 2 1
earth
heart
art
输入2:
3 6
3 2 8
heart
earth
art
Sample Output
输出1:
6
输出2:
16
PS:对于样例1,串是hearth
对于样例2,串是artart
Data Constraint
对于10%的数据N<=5,M<=10
对于40%的数据N<=100,M<=1000
对于100%的数据
N<=200,所以字符串的总长度<=200,M<=10^14
PS:字符串只含小写字母,可能有重复
题解
10%
首先我们考虑一个暴力。
我们设f[i,j]表示当前第i为,填字符j的答案。
显然很好转移。
方程大概是这样的:
统计这个ans应该是很大的。
40%
由于ans不好直接统计并且时间太多。
怎么办?
我们由于要多次寻找字符串。
自然而然地想到AC automation
所以我们建一颗AC自动机并且在上面挂上代价。并且用一个类似于前缀和的东东求出某个点一直跳fail链上所有代价和。设为a[i]
然后设一个b[i,j]数组表示
从AC自动机的i节点后面接上一个j节点的代价。
若b[i,j]=-maxlongint则表示没有意义。(为什么呢?因为我们要保证每次后面接上一个节点一定要可以对答案有贡献)
这个b[i,j]就可以直接利用a数组和AC自动机来求。
于是DP就可以变成:f[i,j]表示第i个位置,放AC自动机上的第j号点的答案。
时间大概是
于是可以在大概的时间内求出。
100%
我们发现,m极其地大,n极其地小。
怎么办?
我们观察dp方程,发现每次f转移时每次代价时一样的。想到什么?矩阵乘法。
但是这个有一个max,不太好搞,怎么办?
一个套路——
由于原来的矩乘是长这样的
我们稍稍变形一下
我们就按照这种形式的矩乘式子弄就好了。
如何证明其满足结合律?
下面是原本矩乘的:
然后我们直接按照这种思路来证明上面的式子就好了。
当然比赛时太急不会证明直接套也是不错的策略。
然后我们只要在矩乘的时候注意一下小细节即可。
代码
{$inline on}
uses math;
type
arr=array[0..201,0..201] of int64;
var
i,j,k,l,n,tot,now:longint;
m,ans:int64;
v:array[1..200] of int64;
s:string;
tree:array[0..40000,1..26] of longint;
a,d,next:array[0..40000] of int64;
f,b:arr;
procedure build_ac_automation;
var
i,j,k,l,head,tail,took,x,y,dep:longint;
begin
head:=1;
tail:=1;
took:=1;
repeat
for dep:=head to tail do
begin
if d[dep]=4 then
j:=j;
for i:=1 to 26 do
begin
if tree[d[dep],i]>0 then
begin
y:=tree[d[dep],i];
x:=next[d[dep]];
while (x>0) and (tree[x,i]=0) do x:=next[x];
if d[dep]>0 then
begin
next[y]:=tree[x,i];
end;
if y<>tree[x,i] then
begin
a[y]:=a[y]+a[tree[x,i]];
end;
inc(took);
d[took]:=y;
end;
end;
end;
head:=tail+1;
tail:=took;
until head>tail;
end;
procedure trie(x,i,up:longint);
var
j,k,l:longint;
begin
if i=up then
begin
a[x]:=a[x]+v[now];
exit;
end;
if tree[x,ord(s[i+1])-96]>0 then
begin
trie(tree[x,ord(s[i+1])-96],i+1,up);
end
else
begin
inc(tot);
tree[x,ord(s[i+1])-96]:=tot;
trie(tree[x,ord(s[i+1])-96],i+1,up);
end;
end;
function cheng(a,b:arr):arr;inline;
var
i,j,k:longint;
c:arr;
begin
fillchar(c,sizeof(c),200);
for i:=0 to tot do
begin
for j:=0 to tot do
begin
for k:=0 to tot do
begin
c[i,j]:=max(c[i,j],a[i,k]+b[k,j]);
end;
end;
end;
exit(c);
end;
function qsm(m:int64):arr;
var
t,y:arr;
i:longint;
begin
t:=b;
y:=b;
while m<>0 do
begin
if(m and 1)=1 then
t:=cheng(t,y);
y:=cheng(y,y);
m:=m shr 1;
end;
exit(t);
end;
begin
//assign(input,'0data.in');reset(input);
fillchar(a,sizeof(a),0);
a[0]:=0;
readln(n,m);
for i:=1 to n do
begin
read(v[i]);
end;
readln;
for i:=1 to n do
begin
readln(s);
now:=i;
trie(0,0,length(s));
end;
build_ac_automation;
fillchar(b,sizeof(b),200);
for i:=0 to tot do
begin
for j:=1 to 26 do
begin
k:=i;
while (k<>0) and (tree[k,j]=0) do k:=next[k];
//if tree[k,j]>0 then
begin
b[i,tree[k,j]]:=a[tree[k,j]];
end;
end;
end;
f:=qsm(m-1);
for i:=0 to tot do
begin
ans:=max(f[0,i],ans);
end;
writeln(ans);
end.