jzoj4649. 【NOIP2016提高A组模拟7.17】项链

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的答案。
显然很好转移。
方程大概是这样的:
f[i,j]:=max(f[i,j],f[i1,k]+ans);f[i,j]:=max(f[i,j],f[i-1,k]+ans);
统计这个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号点的答案。
f[i,j]=max(f[i,j],f[i1,k]+b[k,j])f[i,j]=max(f[i,j],f[i-1,k]+b[k,j])
时间大概是O(n)O(n*很小的数)
于是可以在大概O(mn2)O(m*n^2)的时间内求出。
100%
我们发现,m极其地大,n极其地小。
怎么办?
我们观察dp方程,发现每次f转移时每次代价时一样的。想到什么?矩阵乘法。
但是这个有一个max,不太好搞,怎么办?
一个套路——
由于原来的矩乘是长这样的c[i,j]:=a[i,k]+b[k,j]c[i,j]:=a[i,k]+b[k,j]
我们稍稍变形一下c[i,j]:=max(c[i,j],a[i,k]+b[k,j])c[i,j]:=max(c[i,j],a[i,k]+b[k,j])
我们就按照这种形式的矩乘式子弄就好了。

如何证明其满足结合律?
下面是原本矩乘的:
在这里插入图片描述
然后我们直接按照这种思路来证明上面的式子就好了。
当然比赛时太急不会证明直接套也是不错的策略。

然后我们只要在矩乘的时候注意一下小细节即可。

代码

{$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.
posted @ 2019-05-09 19:02  RainbowCrown  阅读(173)  评论(0编辑  收藏  举报