bzoj 1026: [SCOI2009]windy数 数位dp

来源:互联网 发布:nginx imagefilter 编辑:程序博客网 时间:2024/04/30 00:32

windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,在A和B之间,包括A和B,总共有多少个windy数?

这题很容易就想到数位dp的方法,把求区间转换成求1-A和1-B之间的wendy数。用f[i,j]表示有i位的数且最高位为j时有多少windy数。f[i,j]=sum(f[i-1,k]){abs(j-k)>1}。

关键在于统计。设当前统计的数x的位数为len。

因为不能有前导0,所以就分三步来统计:1、统计位数小于len的wendy数。2、统计位数为len且最高位小于x的windy数。3、再从次高位到个位逐位按照类似步骤(2)的方法统计即可。为了避免前导零的情况,最高位统计时不能将f[i,0]算进去。

代码:

var  i,j,k,n,m:longint;  f:array[1..20,0..9] of longint;function work(x:longint):longint;var  a1,i,j:longint;  a:array[1..30] of longint;begin  a1:=0;  while x>0 do  begin    inc(a1);    a[a1]:=x mod 10;    x:=x div 10;  end;  a[a1+1]:=100;  work:=0;  for i:=a1-1 downto 1 do  begin    for j:=0 to a[i]-1 do      if abs(j-a[i+1])>=2 then work:=work+f[i,j];    if abs(a[i]-a[i+1])<2 then break;  end;  for i:=1 to a[a1]-1 do    work:=work+f[a1,i];  for i:=a1-1 downto 1 do    for j:=1 to 9 do      work:=work+f[i,j];end;begin  for i:=0 to 9 do    f[1,i]:=1;  for i:=2 to 10 do    for j:=0 to 9 do      for k:=0 to 9 do        if abs(j-k)>=2 then f[i,j]:=f[i,j]+f[i-1,k];  readln(n,m);  writeln(work(m+1)-work(n));end.


0 0
原创粉丝点击