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(百位) |
---|---|---|---|
0 | 1 | 3(0、2、3) | 0(首位不为0) |
1 | 1 | 2(1、3) | 5(2+3)(1、3) |
2 | 1 | 2(0、2) | 5(3+2)(0、2) |
3 | 1 | 3(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][i−1]
表示 当前位置的总数=当前位置的数目(初值为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博客