java:K好数(动态规划)

K好数

题目

问题描述
如果一个自然数N的K进制表示中任意的相邻的两位都不是相邻的数字,那么我们就说这个数是K好数。
求L位K进制数中K好数的数目。例如K = 4,L = 2的时候,所有K好数为111320223031337个。由于这个数目很大,请你输出它对1000000007取模后的值。

输入格式
输入包含两个正整数,K和L。

输出格式
输出一个整数,表示答案对1000000007取模后的值。
样例输入
4 2
样例输出
7
数据规模与约定
对于30%的数据,KL <= 106;

对于50%的数据,K <= 16, L <= 10;

对于100%的数据,1 <= K,L <= 100

关于动态规划的小故事(特别值得一看)

https://blog.csdn.net/v_yang_guang_v/article/details/46686441

关于k好数的理解

https://blog.csdn.net/qq_41714549/article/details/87435089

题目理解

1.题目要求的是“L位K进制数中的K好数 的数目”。怎么理解?

首先,要知道K进制数它的取值范围为[0,K-1],如4进制只能取[0,3];16进制为[0,15]等。

其次,明白什么是“L位K进制数”。如:“24进制数”,它是指这个数是个两位数,其中个位数是4进制数(即从[0,3]中取一个数作为个位),十位数也是4进制数。同理,“37进制数”则指这个数是个3位数,其中个位、十位、百位都是7进制数。

最后,按K好数的要求(任意相邻的两位不是相邻的数字)统计就能得到结果。

2.题目中为啥给出“由于数很大……输出取模后的值”这一条件?

首先,要明白“取模运算只有对象是整数间时才等于取余运算”。
最后,在数据规范与约定中,我们知道1K100,1 L​​​​​​​100。我们假设K取100,L也取100。那么在100100进制数中不考虑100好数的情况下,粗略一算,它的数就有100100次方。肯定超过了intlong long。这时题目告诉我们取模来减小我们的负担。(感谢啊)
————————————————
版权声明:本文为CSDN博主「小白鼠零号」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_41714549/article/details/87435089

解题思路

用dp[i][j]=dp[i][j]+dp[i-1][k]来做。解释一下:这里的i 代表所在的位数(i=0代表个位,i=1代表十位,以此类推)。j 代表取K进制数的一个数(如果是4进制数,那么j取[0,3]中的一个数)。k和j同一个意思。整个式子的意思是当前位置的数总数=当前位置的数的数目+前一个位置的数的总数。

以2位4进制数的4好数为例:

dp[1][0]=dp[1][0]+dp[0][k]; k取[0,3] // 十位为0时,添上个位所取得数,看是否满足K好数。结果:dp[1][0]存的是十位为0时的满足4好数的个数,即:1 1、1 3 两种情况。

dp[1][1]=dp[1][1]+dp[0][k]; //同上理解

dp[1][2]=dp[1][2]+dp[0][k];

dp[1][3]=dp[1][3]+dp[0][k];
————————————————
版权声明:本文为CSDN博主「小白鼠零号」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_41714549/article/details/87435089

自己按照上面的理解,画图,这样子方便理解

代码

import java.util.Scanner;

public class k好数 {
	final static int Mod=1000000007;
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner sc=new Scanner(System.in);
		int K=sc.nextInt();//输入K进制
		int L=sc.nextInt();//输入L长度
		int sum=0;
		//横坐标是位数,纵坐标是进制
        //表示l位以k结尾,从1号开始,k中表示1.2.3.···k-1
		int[][] arr=new int[L+1][K];
		for(int i=1;i<=L;i++){
			for(int j=0;j<K;j++)
				arr[i][j]=0;//先进行初始化
		}
		for(int i=0;i<K;i++){//使得第一行中,只有一位数的k好数为1,以K=4为例,0,1,2,3每个数都是只有1位的k好数
			arr[1][i]=1;
		}
		for(int i=2;i<=L;i++){//每位
			for(int j=0;j<K;j++){//每位中k的结尾,这说起来一点都不好理解,自己画图就理解了
				for(int x=0;x<K;x++){
					if(x!=j-1 && x!=j+1){//就是说不相邻
						arr[i][j] += arr[i-1][x];//加上少一位的k的位数的值,先开始的初始值都为0;
						arr[i][j] %=Mod;//进行余数计算
					}
				}
			}
		}
		//把K=0的去掉,不加入sum的值
		for(int j=1;j<K;j++){
			sum +=arr[L][j];
			sum%=Mod;
		}
		System.out.println(sum);
	}

}

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

向上Claire

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

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

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

打赏作者

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

抵扣说明:

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

余额充值