BOZJ1833详细题解
1.题目
Description
给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。
Input
输入文件中仅包含一行两个整数a、b,含义如上所述。
Output
输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次。
Sample Input
1 99
Sample Output
9 20 20 20 20 20 20 20 20 20
说是一道典型的数位dp的问题.首先我们解决什么是数位dp的问题.现在有一个题目,就是要求你求出[l,r]区间内满足一定条件的数的个数,这时我们很容易想到暴力求解的方案,但是一旦数据范围过大这种方法就行不通了,这个时候就用数位dp来解决,把数位拆成一个一个的进位,然后逐一比较看是否满足题目要求.
那么针对这个问题,如何求解呢.
首先我们要做的事情是找到从0-r所含0-9的个数,再用它减去0-l-1的0-9的个数.因为题目要求我们求得是[l,r]必须包括l,这样相减得到的区间恰为[l,r].那么现在我们需要求解的问题是一样的即求某个数x,从[0-x]中所含0-9的个数.
我们用f[i][j][k]来表示长度为i,首位为j,所含k的个数为多少.那么f[i][j][k]是要等于f[i-1][0-9][k],注意我们所要求的是长度为i,首位为j,所含k的个数是多少.举个例子的话就是求200-299所含k的个数是多少.我们抛开首位来看的话,首先我们是不是就要求出00-99所含k的个数是多少再往下推,得到我们需要的递推式.
f[i][j][k] = f[i][j][k] + f[i-1][j][k],这里我们是枚举了从00-99对于之后的首位,从200-299出现100次,所以首位出现的次数就是10i次方,我们再加上即可,此时j == k
那么初始化的函数为
public static void gen() {
pow[1] = 1L;
for (int i = 2; i < 14; i++) {
pow[i] = pow[i - 1] * 10;
}//算10^i
//14是因为题目给的范围就只有那么大
for (int j = 0; j