算法问题:k好数

这篇博客详细介绍了如何利用动态规划解决K进制中K好数的数量问题,通过递推关系展示了从低位到高位如何计算L位K进制的K好数。关键在于理解相邻数字限制的条件并构建dp数组进行计算。最终给出了一个Java代码示例,并提供了样例输入输出和算法思路解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

如果一个自然数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
算法思路

1位4好数就是这个数本身了:1,2,3。
2位4进制数有10,11,12,13,20,21,22,23,30,31,32,33,符合4好数的数有11,13,20,22,30,31,33 共7个。
那3位4进制4好数就有111,113,130,131,133,200,202,203,220,222,300,302,303,311,313,330,331,333 共18个。
从上面可以看出2位4好数可以由1位4好数的结果推出,3位4好数可以由2位4好数的结果推出,那么4位4好数的结果也可以由3位4好数的结果推出。

1位4好数 --> 2位4好数
1 --> 11、13
2 --> 20、22
3 --> 30、31、33
2位4好数 --> 3位4好数
11 -->  111、113
13 -->  130、131、133
20 -->  200、202、203
22 -->  220、222
30 -->  300、302、303
31 -->  311、313
33 -->  330、331、333

L位数时,那我们只要确定第一位数,第二位数不与第一位数相邻,第三位数不与第二位数相邻……用array[i] [j] = array[i] [j] + array[i-1] [k] 来做。

示例代码
import java.util.Scanner;

public class Main{
    final static int num = 1000000007;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int k = scanner.nextInt();
        int l = scanner.nextInt();
        int sum = 0;
        // dp[i][j]中的i表示k好数的位数(i>0),j表示k的范围[0, k-1]
        // dp[i][j]表示i位k好数第i位以j开头的k好数的个数
        // 例如:k=4, l=3时:
        // dp[1][1]表示第1位以1开头的k好数的个数,这个数只有1本身,
        // 故dp[1][1]=1,且dp[1][2]=dp[1][3]=1。
        // dp[2][1]表示第2位以1开头的k好数的个数,这个数有11、13,
        // 故dp[2][1]=dp[1][1]+dp[1][3]。同理,dp[2][0]=dp[1][0]+dp[1][2],dp[2][2]=dp[1][0]+dp[1][2]
        // dp[3][2]表示第3位以2开头的k好数的个数,这个数有20_、22_,_表示任意与上一位不相邻的数,
        // 故dp[3][2]=dp[2][0]+dp[2][2]。
        int[][] dp = new int[l + 1][k];
        // 初始赋值全为0
        for(int i = 0; i < l + 1; i ++){
            for(int j = 0; j < k; j ++){
                dp[i][j] = 0;
            }
        }
        for(int i = 0; i < k; i ++){
            dp[1][i] = 1;
        }
        for(int i = 1; i < l + 1; i ++){
            for(int j = 0; j < k; j ++){
                for(int m = 0; m < k; m ++){
                    if(Math.abs(m - j) != 1){
                        dp[i][j] += dp[i - 1][m];
                        dp[i][j] %= num;
                    }
                }
            }
        }
        for(int i = 1; i < k; i ++){
            sum += dp[l][i];
            sum %= num;
        }
        System.out.print(sum);
        scanner.close();
    }
}

评测结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不负韶华ღ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值