算法训练 K好数
时间限制:1.0s 内存限制:256.0MB
问题描述
如果一个自然数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。
分析:首先我们将四进制下1-3位的K好数写出来,这里把0为开头的K好数也写出来了。
0 | 1 | 2 | 3 |
00 02 03 | 11 13 | 20 22 | 30 31 33 |
000 002 003 020 022 030 031 033 | 111 113 130 131 133 | 200 202 203 220 222 | 300 302 303 311 313 330 331 333 |
…… | …… | …… | …… |
从中可以发现规律:每一个L位K好数都是在L-1位的K好数之上通过某种方式变化得来的。2位的K好数,是由两两不相邻的数组成。3位的K好数是在2位K好数最后添加不相邻的数得来的。
进一步归纳,可得:
0 | 1 | 2 | 3 |
0+0 0+2 0+3 | 1+1 1+3 | 2+0 2+2 | 3+0 3+1 3+3 |
0+00 0+02 0+03 0+20 0+22 0+30 0+31 0+33 | 1+11 1+13 1+30 1+31 1+33 | 2+00 2+02 2+03 2+20 2+22 | 3+00 3+02 3+03 3+11 3+13 3+30 3+31 3+33 |
…… | …… | …… | …… |
可以由此获得递归方程。最后第L行输出除第0列以外的数值的和即可得到答案。
代码:
#include<iostream>
#include<cmath>
#define M 1000000007
using namespace std;
int dp[101][101] = { 0 };
int main() {
int K, L;
cin >> K >> L;
for (int i = 0; i < K; i++) {
dp[1][i] = 1;
}
for (int i = 2; i <= L; i++) {
for (int j = 0; j < K; j++) {
for (int k = 0; k < K; k++) {
if (abs(j - k) != 1) {
dp[i][j] += dp[i - 1][k];
dp[i][j] %= M;
}
}
}
}
int ans = 0;
for (int i = 1; i < K; i++) {
ans += dp[L][i];
ans %= M;
}
cout << ans << endl;
return 0;
}