这是一道比较难的数位dp

因为逐位统计好像无法处理数位和整除原数的

但是有了刚才的bzoj1072的经验,我们能做的是逐位处理被一个数d整除的方案

不难想到先穷举数位和now,now最大也就162,可以承受

然后在统计数位和为now且能整除原数的方案

我们用f[less,i,j,k]表示第i位是否必须小于n的第i位,还有i位没处理,当前数位和为j,处理过的数位mod now余数为k的方案

然后记忆化搜索就可以了(转移见程序)

 1 var f:array[0..1,0..20,0..170,0..170] of int64;
 2     a:array[0..20] of longint;
 3     len,t,now,i:longint;
 4     l,r,ans:int64;
 5 
 6 function max(a,b:longint):longint;
 7   begin
 8     if a>b then exit(a) else exit(b);
 9   end;
10 
11 function calc(p,i,j,k:longint):int64;
12   var w,ch,s,t:longint;
13       sum:int64;
14   begin
15     sum:=0;
16     if i=0 then
17       if (j=0) and (k=0) then exit(1)
18       else exit(0);
19     if f[p,i,j,k]<>-1 then exit(f[p,i,j,k]); //记忆化
20     s:=max(0,j-9*(i-1));
21     if p=0 then t:=a[i] else t:=9;
22     for w:=s to t do //穷举这位的数
23     begin
24       if (p=0) and (w=a[i]) then ch:=0
25       else ch:=1;
26       sum:=sum+calc(ch,i-1,j-w,((k*10 mod now)+w) mod now); 转移
27     end;
28     f[p,i,j,k]:=sum;
29     exit(sum);
30   end;
31 
32 procedure work(x:int64);
33   begin
34     t:=0;
35     while x<>0 do
36     begin
37       inc(t);
38       a[t]:=x mod 10;
39       x:=x div 10;
40     end;
41   end;
42 
43 function count(p:int64):int64;
44   begin
45     work(p);
46     fillchar(f,sizeof(f),255);
47     exit(calc(0,t,now,0));
48   end;
49 
50 begin
51   readln(l,r);
52   len:=trunc(ln(r)/ln(10))+1;
53   for now:=1 to 162 do
54   begin
55     if now>len*9 then break;  //小优化
56     ans:=ans+count(r)-count(l-1);
57   end;
58   writeln(ans);
59 end.
View Code

 

posted on 2014-08-28 22:31  acphile  阅读(197)  评论(0编辑  收藏  举报