jzoj2742. 【PKU1625】Censored!

Description

给出p个长度不超过10的字符串,字符集大小为n。
如果这p个串都不是字符串s的子串,则认为s是幸运的。
求长度为m的幸运串个数。

Input

第一行三个正整数n,m,p。
第二行n个不同的字符,表示字符集,其ASCII码大于32。
接下来p行每行一个字符串,表示不允许被包含的串。

Output

一行一个整数,表示幸运串个数。

Sample Input

2 3 1
ab
bb

Sample Output

5

Data Constraint

对于20%的数据,m ≤ 6,n ≤ 10;
对于50%的数据,p个串的长度不超过4,m ≤ 50,n ≤ 10;
对于100%的数据,n ≤ 50,m ≤ 50,p ≤ 10。

Hint

aaa aab aba baa bab 共5个串为幸运串。

题解

这题首先我们看到找出p字符串不为子串的字符串方案数。
想到什么?AC_Automation of course
如果不会AC_Automation也就是AC自动机的话,先学学也可。
其实这玩意就是trie+kmp。
于是我们把p字符串建立一颗AC自动机,然后在结尾挂上一个标记(注意fail边要下传!!!)
接下来我们考虑DP
f[i,j]f_{[i,j]}表示当前建立新字符串建到第ii位时,AC自动机上走到了jj这个位置。
初始化f[0,0]=1f_{[0,0]}=1
然后我们枚举i1i-1走到了jj状态,再枚举当前位放第kk个字符。
然后跳fail链,跳到的位置记为lastlast。同时判断一下有没有走到标记即可
方程:
f[i,last]+=f[i1,j]f_{[i,last]}+=f_{[i-1,j]}
很清真,很简单。
然后出题人就硬是要你套个高精度加法。
时间复杂度:O(mnlen(p)x())O(m*n*len(表示p字符串总大小)*x(高精度的时间))

代码

uses math;
var
        i,j,k,l,n,m,p,tot:longint;
        id:array[1..1000] of longint;
        tree:array[0..5000,0..200] of longint;
        d,next:array[0..50000] of longint;
        an,ka,kb:array[1..200] of longint;
        f:array[0..100,0..200] of ansistring;
        bz:array[1..5000] of boolean;
        s,c:string;
        ans:ansistring;
function jia(a,b:ansistring):ansistring;
var
        i,j,k,l,lena,lenb,len:longint;
        c:ansistring;
begin
        lena:=length(a);lenb:=length(b);
        if (lena>lenb) or ((lena=lenb) and (a>b)) then
        begin
                c:=a;a:=b;b:=c;
                l:=lena;lena:=lenb;lenb:=l;
        end;
        j:=1;for i:=1 to lena do begin ka[i]:=ord(a[j])-48; inc(j); end;
        j:=1;for i:=1 to lenb do begin kb[i]:=ord(b[j])-48; inc(j); end;
        an:=kb;
        k:=0;j:=0;l:=lenb;
        for i:=lena downto 1 do
        begin
                j:=ka[i]+kb[l]+k;
                k:=j div 10;
                j:=j mod 10;
                an[l]:=j;
                dec(l);
        end;
        c:='';
        while k>0 do
        begin
                if l>0 then
                begin
                        j:=kb[l]+k;
                        k:=j div 10;
                        j:=j mod 10;
                        an[l]:=j;
                        dec(l);
                end
                else
                begin
                        c:=c+chr(k+48);
                        break;
                end;
        end;
        for i:=1 to lenb do
        begin
                c:=c+chr(an[i]+48);
        end;
        exit(c);
end;
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
                        for i:=1 to n 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
                                                if bz[tree[x,i]] then bz[y]:=true;
                                        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
                bz[x]:=true;
                exit;
        end;
        if tree[x,id[ord(s[i+1])]]>0 then
        begin
                trie(tree[x,id[ord(s[i+1])]],i+1,up);
        end
        else
        begin
                inc(tot);
                tree[x,id[ord(s[i+1])]]:=tot;
                trie(tree[x,id[ord(s[i+1])]],i+1,up);
        end;
end;
begin
        //assign(input,'consored.in');reset(input);
        readln(n,m,p);
        readln(c);
        tot:=0;
        for i:=1 to n do
        begin
                inc(tot);
                id[ord(c[i])]:=tot;
                tree[0,tot]:=tot;
        end;
        for i:=1 to p do
        begin
                readln(s);
                trie(0,0,length(s));
        end;
        build_ac_automation;
        f[0,0]:='1';
        for i:=1 to m do
        begin
                for j:=0 to tot do
                begin
                        if (length(f[i-1,j])>0) then
                        begin
                                for k:=1 to n do
                                begin
                                        l:=j;
                                        while (l>0) and (tree[l,k]=0) do l:=next[l];
                                        if not bz[tree[l,k]] then
                                        begin
                                                if (length(f[i,tree[l,k]])=0) then f[i,tree[l,k]]:='0';
                                                f[i,tree[l,k]]:=jia(f[i,tree[l,k]],f[i-1,j]);
                                        end;
                                end;
                        end;
                end;
        end;
        for i:=1 to tot do
        begin
                ans:=jia(ans,f[m,i]);
        end;
        writeln(ans);
end.
posted @ 2019-06-26 14:31  RainbowCrown  阅读(177)  评论(0编辑  收藏  举报