比较恶心的题目
不难发现是在自动机上做数位dp
注意要考虑前导0,题目中给出的233是幸运数,20233不是
为此我非常猥琐的写了一个四维dp,用记忆化搜索实现

  1 const mo=1000000007;
  2 var dp:array[0..1,0..1,0..1205,0..1505] of longint;
  3     trie:array[0..2005,'0'..'9'] of longint;
  4     q,f:array[0..2005] of longint;
  5     can:array[0..2005] of boolean;
  6     ans,i,n,m,t,j,k,l:longint;
  7     s,ss:ansistring;
  8     ch:char;
  9 
 10 procedure ac;
 11   var h,r,i,x,y:longint;
 12       c:char;
 13   begin
 14     h:=1;
 15     r:=0;
 16     for c:='0' to '9' do
 17       if trie[0,c]>0 then
 18       begin
 19         inc(r);
 20         q[r]:=trie[0,c];
 21       end;
 22 
 23     while h<=r do
 24     begin
 25       x:=q[h];
 26       for c:='0' to '9' do
 27         if trie[x,c]>0 then
 28         begin
 29           y:=trie[x,c];
 30           inc(r);
 31           q[r]:=y;
 32           j:=f[x];
 33           while (j>0) and (trie[j,c]=0) do j:=f[j];
 34           f[y]:=trie[j,c];
 35           if can[trie[j,c]] then can[y]:=true; //注意
 36         end;
 37       inc(h);
 38     end;
 39   end;
 40 
 41 function calc(p,z,i,j:longint):longint; //p表示当前位置上的数是否需要小于N当前位上的数
 42                                         //z表示假如当前位出现0,是否是多余的0  
 43   var k,q,zz:longint;
 44       s,c,e:char;
 45   begin
 46     if can[j] then exit(0);
 47     if i=m then exit(1);
 48     if dp[p,z,i,j]<>-1 then exit(dp[p,z,i,j]);
 49     dp[p,z,i,j]:=0;
 50     if p=0 then e:=ss[i+1] else e:='9';
 51     for c:='0' to e do
 52     begin
 53       if (p=0) and (c=e) then q:=0
 54       else q:=1;
 55       k:=j;
 56       while k>-1 do
 57       begin
 58         if trie[k,c]>0 then break;
 59         k:=f[k];
 60       end;
 61       if k=-1 then k:=0 else k:=trie[k,c];
 62       if (z=0) and (c='0') then  //开头多余的0不考虑
 63       begin
 64         zz:=0;
 65         k:=0;  //多余的0不在自动机上匹配
 66       end
 67       else zz:=1;
 68       dp[p,z,i,j]:=(dp[p,z,i,j]+calc(q,zz,i+1,k)) mod mo;
 69     end;
 70     exit(dp[p,z,i,j]);
 71   end;
 72 
 73 begin
 74   read(ch);
 75   while ch='0' do read(ch);
 76   readln(ss);
 77   ss:=ch+ss;
 78   m:=length(ss);
 79   f[0]:=-1;
 80   readln(n);
 81   for i:=1 to n do
 82   begin
 83     readln(s);
 84     j:=0;
 85     l:=length(s);
 86     for k:=1 to l do
 87     begin
 88       if trie[j,s[k]]=0 then
 89       begin
 90         inc(t);
 91         trie[j,s[k]]:=t;
 92       end;
 93       j:=trie[j,s[k]];
 94     end;
 95     can[j]:=true;
 96   end;
 97   ac;
 98   fillchar(dp,sizeof(dp),255);
 99   ans:=(calc(0,0,0,0)-1+mo) mod mo;
100   writeln(ans);
101 end.
View Code

 

posted on 2015-02-07 11:00  acphile  阅读(134)  评论(0编辑  收藏  举报