这是一道比较难的数位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.