JZOJ 4886 字符串 KMP+DP

10 篇文章 0 订阅

Description

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

Input

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

Output

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

Sample Input

5
a

Sample Output

9765625

Data Constraint

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

真是水的不行。。快速列出方程式f[i,j]表示原串匹配到i位,危险串匹配到j位,然后直接DP
方程式是f[i+1,g[j,k]]+=f[i,j];g[j,k]表示第j+1位失配时那个失配数组指向的位置,k是字符。。然而我考场上算了算,状态数还没有转移就达到了2e7(100*10000*26),这不是会爆?于是用了矩阵快速幂来优化状态转移,,结果被逗了。。还打错了,只有30分。。MDZZ。。

uses math; 
const mo=1000000007;
var
        i,j,k,p,n,m:longint;
        s:ansistring;
        c:char;
        f:array[0..10000,0..100]of longint;
        next:array[0..100000]of longint;
        g:array[0..10000,0..26]of longint;
        ans:longint;
begin
     assign(input,'helloworld.in');
     assign(output,'helloworld.out');
     reset(input);
     rewrite(output);
        while true do
        begin
                readln(n);
                readln(s);        
                if n=0then break;
m:=length(s);
                s:=s+'#';

                fillchar(f,sizeof(f),0);
                fillchar(next,sizeof(next),0);
                j:=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;
                fillchar(g,sizeof(g),0);
                for i:=0 to m-1 do
                begin
                        for c:='a'to'z' do
                        begin
                                j:=i;
                                while(j>0)and(s[j+1]<>c)do j:=next[j];
                                if s[j+1]=c then inc(j);
                                g[i,ord(c)-97]:=j;
                        end;
                end;
                f[0,0]:=1;
                for i:=1 to n do
                begin
                        for j:=min(i,m)-1 downto 0 do
                        begin
                                for k:=0 to 25 do
                                f[i,g[j,k]]:=(f[i,g[j,k]]+f[i-1,j])mod mo;
                        end;
                end;
                ans:=0;
                for i:=0 to m-1 do
                ans:=(ans+f[n,i])mod mo;
                writeln(ans);
        end;
end.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值