[BZOJ1026][SCOI2009]windy数 解题报告|数位dp
Description
windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,在A和B之间,包括A和B,总共有多少个windy数?
一直还是有点怕数位DP的...包括今天做这道简单的小题也花了很久的时间处理细节。
首先大体的思路非常明显,定义一个DP f[i,j]表示第i位放数字j有多少种方法,可以通过前一位的一些满足的数字推出这一位。
但是如何来解决在某个数A的范围内呢...?
并且一旦前面的没有取满,这一位都是可以0..9任意取的
并且还要考虑以这一位为开头的情况
没有前导零,也就是说当这一位为0的时候是不能作为开头的。
思考了一会儿,想出了一种方案。f[i,j]表示第i为放数字j并且从1~i并排除取到原数的方案数
那么通过f[i-1]然后枚举0~9就可以先得出初步的f[i](因为i-1位以前都没有取到满了,这一位随便怎么取都不会超过原数)
第二部分就是当前数为起点,那么我们枚举1~9,inc(f[i][j])就可以了
还有一种情况,就是i-1位已经取满了,当前这位只能取0~num[i]这些数(num[i]表示原数在第i位的数字)
但是我们只能枚举到num[i]-1,因为要维护f[i]这个数组的性质:没有取到满
注意细节:第三种情况能够转移当且仅当1~i-1位都满足windy数的性质 (这里我们可以用一个bool类型标记)
处理完之后再判断1~i是否满足windy数的性质
f[最后一位][0..9]就是答案。
其实还没有结束...别忘了原数,如果那个bool类型到最后还是为真,说明原数也是一个windy数
但是显然我们在f数组里是不会统计到原数的,这个时候还要答案+1
最后还有一个细节,就是特判0的情况,虽然题目保证>=1但是我们要的答案是solve(r)-solve(l-1),还是会即算到0的情况
要特判solve(0)=0
前几天写惯了树剖今天几道小题真是爽啊...
1 /************************************************************** 2 Problem: 1026 3 User: mjy0724 4 Language: Pascal 5 Result: Accepted 6 Time:0 ms 7 Memory:228 kb 8 ****************************************************************/ 9 10 program bzoj1026; 11 var i,l,r:longint; 12 w,num:array[-1..15]of longint; 13 f:array[-1..15,0..9]of longint; 14 15 function solve(p:longint):longint; 16 var i,j,k,ans:longint; 17 flag:boolean; 18 begin 19 if p=0 then exit(0); 20 fillchar(f,sizeof(f),0); 21 for i:=9 downto 1 do if p div w[i]>0 then break; 22 if p div w[i]>0 then inc(i); 23 for j:=i downto 1 do num[j]:=p div w[j-1] mod 10; 24 for j:=1 to num[i]-1 do f[i,j]:=1; 25 flag:=true; 26 for i:=i-1 downto 1 do 27 begin 28 for j:=0 to 9 do 29 for k:=0 to 9 do if abs(j-k)>=2 then inc(f[i,j],f[i+1,k]); 30 for j:=1 to 9 do inc(f[i,j]); 31 if flag then for j:=0 to num[i]-1 do if abs(j-num[i+1])>=2 then inc(f[i,j]); 32 if abs(num[i]-num[i+1])<2 then flag:=false; 33 end; 34 ans:=0; 35 for i:=0 to 9 do inc(ans,f[1,i]); 36 if flag then inc(ans); 37 exit(ans); 38 end; 39 40 41 begin 42 w[0]:=1; 43 for i:=1 to 9 do w[i]:=w[i-1]*10; 44 readln(l,r); 45 writeln(solve(r)-solve(l-1)); 46 end.