helloworld

Description

某日mhy12345在教同学们写helloworld,要求同学们用程序输出一个给定长度的字符串,然而发现有些人输出了一些“危险”的东西,所以mhy12345想知道对于任意长度 n  n 的小写字母字符串,不包含危险串的字符串个数

Input

多组数据,以 EOF  EOF 结束。对于每组数据,第一行一个数 n n,表示字符串的长度,第二行一个字符串 str  str 表示危险串。

Output

对于每组数据,输出一个整数表示答案 mod(109+7)mod(109+7)的值。

Sample Input

5
a

Sample Output

9765625

Data Constraint

对于10%10%的数据,|str|=1|str|=1
对于另30%30%的数据,n5n≤5
对于另30%30%的数据,危险串不存在相同字符
对于100%100%的数据,0|str|100,0n100000≤|str|≤100,0≤n≤10000

Solution

考试时想过用容斥,但好像不可做……所以就换了一种方式——DP
设状态 f[i,j]  f[i,j]  为当前已经做到第i位,已匹配了前j位危险串的合法方案数。
那么对于不存在相同字符的串就有如下转移:
当下一位选 S[j+1]  S[j+1] 时,转移到f[i,j+1]f[i,j+1]
当下一位选 S[1]  S[1] 时,转移到 f[i,1]  f[i,1] 
选其它,转移到 f[i,0]  f[i,0] 
对于存在相同字符的串,那就稍微有些不同了。
。由于给定串可能包含重复字母,因此
下一位不选  s[j+1]  s[j+1] 时,不一定转移到  f[i,0]  f[i,0] ,而是可能转移到
f[i][next[j]+1]f[i][next[j]+1]f[i][next[next[j]]+1]f[i][next[next[j]]+1]f[i][next[next[next[j]]]+1]f[i][next[next[next[j]]]+1]……其中
next 数组是 kmp 的 next 数组,具体转移到哪个要
看下一位具体选什么。
所以我们预处理一个p[j,k]数组,表示选j字符最多可以匹配到第几位。反之如果不匹配到最多的那一位就有可能提前匹配了一个危险串,就会有不合法的可能。
所以就有 f[i+1,p[j,k]]+=f[i,j]  f[i+1,p[j,k]]+=f[i,j] 

Code

一个 90  90 分代码,求找bug。

    const   mo=1000000007;
    var     m,i,j,k:longint;
            n,ans:int64;
            c:array[1..26] of char;
            p:array[0..105,1..26] of longint;
            next:array[1..105] of longint;
            f:array[0..10005,0..105] of int64;
            s:string;
    function min(x,y:longint):longint;
    begin
            if x<y then exit(x);exit(y);
    end;
    begin
        for i:=1 to 26 do c[i]:=chr(ord('a')+i-1);
        while not eof do begin
            readln(n);
            readln(s);
            m:=length(s);ans:=0;
            fillchar(next,sizeof(next),0);
                    fillchar(p,sizeof(p),0);
                    fillchar(f,sizeof(f),0);
            for i:=2 to m do begin
                while (j<>0) and (s[i]<>s[j+1]) do j:=next[j];
                if s[i]=s[j+1] then inc(j);
                next[i]:=j;
            end;
            for i:=0 to m-1 do begin
                for j:=1 to 26 do begin
                        k:=i;
                        while (k<>0) and (c[j]<>s[k+1]) do k:=next[k];
                        if c[j]=s[k+1] then k:=k+1;
                        p[i,j]:=k;
                end;
            end;
            for i:=0 to n-1 do begin
                for j:=0 to min(m-1,i) do begin
                    for k:=1 to 26 do begin
                        f[i+1,p[j,k]]:=(f[i+1,p[j,k]]+f[i,j]) mod mo;                                        
                    end;
                end;
            end;
            for i:=0 to m-1 do ans:=(ans+f[n,i]) mod mo;
            writeln(ans);
        end;
    end.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值