数位dp = dfs + 记忆化
主要思路
1.dfs本是暴力解决问题的一种方法,数位dp是利用动态规划是思想把以前搜索过的过程记录下来,如果到下一次需要这个结果是就可以直接返回这个值,不需要再从新计算了
2.一般我们是从高位往低位搜索,如果我们需要的结果dp数组里面有我们就不需要从新计算了,如果搜索到了个位就返回一(就是本身)
3.还有我们搜索的时候一定要判断是否到达了边界,不然超出我们所要统计的数的范围
HDU2089 AC代码
import java.util.Scanner;
public class Main {
public static int[] digit;
public static long[][] dp;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
long n = sc.nextLong();
long m = sc.nextLong();
if(n==0&&m==0)break;
System.out.println(solve(m)-solve(n-1));
}
}
public static long solve(long sum) {
int k = 0;
digit = new int[20];
dp = new long[20][2];
while(sum!=0) {
digit[++k] = (int) (sum%10); //从1开始复值,0位站位符
sum/=10;
}
return dfs(k,false,true); //第k位有上限,所以第二个参数是true;
}
private static long dfs(int len, boolean if6, boolean limit) {
if(len==0) return 1; //len=0,统计个位,就是本身 1个
if(!limit&&dp[len][if6?1:0]!=0) return dp[len][if6?1:0]; //记忆化搜索,前面有值的直接返回,就不需要计算了
long cnt = 0,up_bound = limit ? digit[len]:9; //确定dfs的边界
for (int i = 0; i <= up_bound; i++) { //把下面的状态都加起来给当前的状态!
if(if6&&i==2) continue;
if(i==4) continue;
cnt += dfs(len - 1,i==6,limit&&i==up_bound);
}
if(!limit) dp[len][if6?1:0] = cnt; //这个状态是没有约束条件的
return cnt;
}
}