• 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.
    
  • 相关阅读:
    【XSY1544】fixed 数学 强连通图计数
    【XSY1538】连在一起的幻想乡 数学 无向连通图计数
    拉格朗日插值
    【XSY1537】五颜六色的幻想乡 数学 生成树计数 拉格朗日插值
    【XSY1528】azelso 概率&期望DP
    【BZOJ2655】calc DP 数学 拉格朗日插值
    【XSY1529】小Q与进位制 分治 FFT
    【XSY1519】彩灯节 DP 数学 第二类斯特林数
    CODEFORCES掉RATING记 #5
    【BZOJ3992】【SDOI2015】序列统计 原根 NTT
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11148360.html
Copyright © 2020-2023  润新知