资源限制
内存限制:256.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s
问题描述
如果一个自然数N的K进制表示中任意的相邻的两位都不是相邻的数字,那么我们就说这个数是K好数。求L位K进制数中K好数的数目。例如K = 4,L = 2的时候,所有K好数为11、13、20、22、30、31、33 共7个。由于这个数目很大,请你输出它对1000000007取模后的值。
输入格式
输入包含两个正整数,K和L。
输出格式
输出一个整数,表示答案对1000000007取模后的值。
样例输入
4 2
样例输出
7
数据规模与约定
对于30%的数据,KL <= 106;
对于50%的数据,K <= 16, L <= 10;
对于100%的数据,1 <= K,L <= 100。
解题思路
采用动态规划的方法,将大问题分解为小问题,求最优化。
题目需要求的是,K进制下的L位数满足K好数的个数,那么可以将L位数分解为小问题,即,从首位开始考虑(称为第1位),在考虑第2位时,则需要在第1位是K数的基础上,考虑第2位,依次类推。
每一个数位的可能性有(K-1)种,所以可以构建一个二维数组。如下图所示:
(L+1)行K列
i表示第i数位(从左往右数),j表示该数为数字为j。(为了匹配数位和矩阵下标,故选取L+1行)
(i,j)位置的数据表示的是:第i数位数字为j时,K数的个数。
初始化第i=0行的数据为0。
分析可得,当i=1时,即数字只有一位,那么除了0以外,其余数字都是K数。
即1、2、3都是K数,因此都有1个
故填表如下:
接着,当i>1时,如i=2,即第2位,j=0,即第二位为0时。 如下图所示:考虑第2位数为0时,会有00、10、20、30,其中00不是两位数,10不满足K数要求,故满足要求的只有2种。也可以参照i=1行的数可知,第2位数为0时,一共需要三个数相加即可。
接着,当i>1时,如i=2,即第2位,j=1,即第二位为1时。 如下图所示:考虑第2位数为1时,会有01、11、21、31,其中01不是两位数,21不满足K数要求,故满足要求的只有2种。也可以参照i=1行的数可知,第2位数为1时,一共需要两个数相加即可。
接着,当i>1时,如i=2,即第2位,j=2,即第二位为2时。 如下图所示:考虑第2位数为2时,会有02、12、22、32,其中02不是两位数,12、32不满足K数要求,故满足要求的只有1种。也可以参照i=1行的数可知,第2位数为2时,一共需要两个数相加即可。
接着,当i>1时,如i=2,即第2位,j=3,即第二位为3时。 如下图所示:考虑第2位数为3时,会有03、13、23、33,其中03不是两位数,23不满足K数要求,故满足要求的只有2种。也可以参照i=1行的数可知,第2位数为3时,一共需要三个数相加即可。
因此总结可得,(i,j)的个数计算可有上一行所有相加再减去不满足K数条件的即可,也就是说减去上一行相邻的两个数(i-1,j-1)与(i-1,j+1),为防止下标溢出,一共分为三种情况:
(1)j=0时,只减去(i-1,j+1)
(2)j=K-1时,只减去(i-1,j-1)
(3)j在中间时,减去两个(i-1,j-1)与(i-1,j+1)
也可以总结为,除去(i-1,j-1)与(i-1,j+1)其余都加起来。
以此类推,可以算出所有值如下图所示:
所以数位L的所有K数满足要求的,就是第L行所有数字之和。如例题中K=4,L=2,即四进制的2位数中K数的个数,即第2行所有个数相加(2+2+1+2)=7。
要注意一点是,数很大,需要采用long类型而非int类型,同时为了防止数字过大,在存储时,就可以存储该数取模后的数,即result%1000000007。
具体代码如下:
import java.util.Scanner;
public class Main{
public static void main(String args[]) {
Scanner in = new Scanner(System.in);
int K = in.nextInt();//K进制
int L = in.nextInt();//L位数
final int M = 1000000007;
long result = 0;
//初始化动态规划矩阵(位数为1时的情况)
long[][] array = new long[L+1][K];
array[1][0] = 0;
for(int l=1;l<K;l++) {
array[1][l] = 1;
}
//动态遍历填表(如果位数大于1)
if(L>1) {
for(int i=2;i<=L;i++) {
for(int j=0;j<K;j++) {
//除去上一行相邻的两个数,其余都加起来
for(int m=0;m<K;m++) {
if((m!=j-1) && (m!=j+1)) {
array[i][j] = (array[i][j]+array[i-1][m]) % M;
}
}
}
}
}
for(int n=0;n<K;n++) {
result += array[L][n];
}
System.out.println(result % M);
}
}
参考: