[C++]动态规划——K好数

文章介绍了K好数的概念,即在特定进制下任何相邻两位不相邻的数字组成的数。对于给定的L位K进制数,要求求出K好数的个数,并对10^9+7取模。文章通过分析特殊情况和使用动态规划的方法解决了该问题,其中关键在于利用二维数组dp记录每个数位的K好数个数,并通过转移方程更新状态。最后,代码实现并解释了对1e9+7取模的必要性,以防数值溢出。
摘要由CSDN通过智能技术生成

K好数

问题描述

如果一个自然数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

在理解题意后,按照K好数的定义来暴力解决必然会超时(蓝桥杯运行超时也是有分的)

特殊情况

先考虑边界等特殊情况,看能不能骗骗分。

1进制1位,只有0一个数,不知道算不算K好数,试一试。

if (K == 1 && L == 1)
        cout << 0 << endl;

在这里插入图片描述

尝试得知,1进制下,0不算K好数,10分到手。猜测0在1进制下没有相邻的数。

接下来,试了 K进制1位 (K>1),没有得分。

思路

在思索许久后,发现这个问题可以拆分为多个子问题,以4进制3位数为例:

4进制时,每个数位可取0、1、2、3

  • 当百位为1时,十位可取1、3,再考虑个位

    当十位为1时,个位可取1、3

    当十位为3时,个位可取0、1、3

  • 当百位为3时,十位可取0、1、3,再考虑个位

    当十位为0时,个位可取0、2、3

    当十位为1时,个位可取1、3

    当十位为3时,个位可取0、1、3

在同一进制下,当一个K好数的高位确定时,低位的选择也确定了。

在4进制下

3位数的K好数的数目=百位为1、2、3的K好数的数目之和

百位为1的K好数=十位为1、3的K好数之和

十位同理

进制\数位0(个位)1(十位)2(百位)
013(0、2、3)0(首位不为0)
112(1、3)5(2+3)(1、3)
212(0、2)5(3+2)(0、2)
313(0、1、3)8(3+2+3)(0、1、3)

用二维数组来存储某个数位下的K好数个数,关系如下
d p [ j ] [ i ] = d p [ j ] [ i ] + d p [ k ] [ i − 1 ] dp[j][i] = dp[j][i] + dp[k][i - 1] dp[j][i]=dp[j][i]+dp[k][i1]
表示 当前位置的总数=当前位置的数目(初值为0)+前一个位置的总数

i:i ≥ 1(从十位起),表示数位,用0、1、2…表示个位、十位、百位…

j:取值为[0,K-1],表示第i位上的值(当前位)

k:取值为[0,K-1],表示第i-1位上的值(上一位)

注意区分大小写

代码
#include <iostream>
#include <cmath>
using namespace std;

int main()
{
    int K, L;
    cin >> K >> L;
    int dp[110][110] = {0};

    if (K == 1 && L == 1)
        cout << 0 << endl;
    else if (K > 1 && L == 1)
        cout << K << endl;
    else if (K > 1)
    {
        for (int i = 0; i < K; i++)
            dp[i][0] = 1;

        for (int i = 1; i <= L; i++)
            for (int j = 0; j < K; j++)
                for (int k = 0; k < K; k++)
                {
                    if (abs(j - k) != 1)
                    {
                        if (j == 0 && i == L - 1)
                            continue;
                        dp[j][i] = dp[j][i] + dp[k][i - 1];
                        dp[j][i] %= 1000000007;
                    }
                }

        int count = 0;
        for (int i = 0; i < K; i++)
        {
            count += dp[i][L - 1];
            count %= 1000000007;
        }
        cout << count << endl;
    }
    system("pause");
    return 0;
}
关于对1e9+7取模

一开始提交代码时,不能完全通过,只能通过部分测试。搞了半天才发现是取余的原因。

在这里插入图片描述

随着K和L取值的增大,K好数的数量会迅猛增长,超过int的范围,导致返回值错误。

所以,在每次计算dp[i][j]时都应该对其进行dp[j][i] %= 1000000007操作
在这里插入图片描述

参考

【算法基础】大数求余:即为什么有些答案总要对1e9+7(1000000007)取模?_对1e9+7取模_TomLazy的博客-CSDN博客

算法训练 K好数 (详解:题目理解+解题思路)_小白鼠零号的博客-CSDN博客

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值