蓝桥杯:K好数 动态规划解法

こ雲淡風輕ζ 提交于 2020-02-04 04:34:47

蓝桥杯: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

数据规模与约定

对于30%的数据,KL <= 106
对于50%的数据,K <= 16, L <= 10;
对于100%的数据,1 <= K,L <= 100。

思路

  • 因为数字不能相邻,那么第 i 位的填写,取决于第 i-1 位的数字

若第 i-1 位数字为 0 或者 k-1,第 i 位有 k-1 种选择

例:四进制,可选0,1,2,3
现有长度位2的数字:30,现在填第三位,可以选0,2,3
现有长度位2的数字:13,现在填第三位,可以选0,1,3

若第 i-1 位数字为 1~k-2,第 i 位有 k-2 种选择

例:四进制,可选0,1,2,3
现有长度位2的数字:31,现在填第三位,可以选1,3
现有长度位2的数字:12,现在填第三位,可以选0,2

那么长度为len,结尾数字为 x 的K好数的数目,就是

所有【长度为len-1,结尾数字与x不相邻的K好数的数目】之和

  • 这样,大问题就被拆解为小问题,即长度为len的K好数数目和长度为len-1的K好数数目相关

可以定义状态:
dp[i][j]表示以i结尾,长度为j的K好数的数目

状态转移方程:(Sum表示求和)

dp[i][j] = Sum(dp[0~k-1之间与i不相邻的数字][j-1])

代码

需要注意的是取余数,每一步运算之后都要取余数

#include <iostream>
#include <cmath>

using namespace std;

#define MAXLEN 109
#define mod 1000000007
#define iabs(x) ((int)fabs(x))
int dp[MAXLEN][MAXLEN];	// dp[i][j]表示以i结尾,长度为j的K好数的数目
int k, l;

int main()
{
	cin>>k>>l;
	// 不能以0打头,长度为1,结尾=开头
	dp[0][1] = 0;	 
	// dp数组初始化:以1~k-1结尾,长度为1的K好数数目是1 
	for(int i=1; i<k; i++)
	{
		dp[i][1] = 1;
	}
	
	// DP 
	for(int i=2; i<=l; i++)
	{
		for(int j1=0; j1<k; j1++)
		{
			// 以j1结尾,长度为i的K好数数目 =
			// 所有长度为i-1,结尾数字与j1不相邻的K好数的数目之和 
			int sum = 0;
			for(int j2=0; j2<k; j2++)
			{
				if(iabs(j1-j2)>1 || j1==j2)
				{
					sum += dp[j2][i-1]%mod;
					sum = sum%mod;
				}
			}
			dp[j1][i] = sum%mod;
		}
	}
	
	// 计算以任意数字结尾,长度为l的K好数数目 
	int cnt = 0;
	for(int i=0; i<k; i++)
	{
		cnt += dp[i][l]%mod;
		cnt = cnt%mod;
	}
	cout<<cnt%mod<<endl;
	
	return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!