helloworld

5 篇文章 0 订阅
1 篇文章 0 订阅

Description

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

Input

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

Output

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

Sample Input

5
a

Sample Output

9765625

Data Constraint

对于 10% 10 % 的数据, |str|=1 | s t r | = 1
对于另 30% 30 % 的数据, n5 n ≤ 5
对于另 30% 30 % 的数据,危险串不存在相同字符
对于 100% 100 % 的数据, 0|str|100,0n10000 0 ≤ | s t r | ≤ 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 ] [ n e x t [ j ] + 1 ] f[i][next[next[j]]+1] f [ i ] [ n e x t [ n e x t [ j ] ] + 1 ] f[i][next[next[next[j]]]+1] f [ i ] [ n e x t [ n e x t [ n e x t [ 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.

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值