蓝桥杯 K好数(动态规划)

本文介绍了一种利用动态规划求解特定条件下K好数的数量的方法。针对一个自然数N,在其K进制表示中,任意相邻的两位数字都不相邻时,称此数为K好数。通过动态规划算法计算L位数中的K好数目,并输出结果对1000000007取模后的值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  算法训练 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。


问题分析:

使用动态规划。

参考文献:键盘上的舞者的博客:http://blog.csdn.net/libin56842/article/details/19910663

dp[i][j],其中 i 表示总共有多少位(i<=L),j 表示最后面那个数字(j<K)

我们是这样动态规划的:

总共1位:  全部初始化为1,方便dp[2][j]  规划。

总共2位:......  (还是直接看下面的数组吧)。

当输入:>> 4 2  时,如下:(行i<L,列:表示K进制(4进制{0,1,2,3}))

 0123
11111
23223
所以:7 = 2 + 2 + 3

ps:我们每次往后面加一个数字(列 表示所追加的数字,行表示现在有多少位)

附录:

/*
	Name: 蓝桥杯:K好数 
	Copyright: Analyst 
	Author: Analyst 
	Date: 02/03/14 22:07
	Description: dev-cpp 5.5.3
*/
#include <stdio.h>
int main()
{
	int K,L,i,j,x;
	long long sum = 0,dp[500][105];  
	
	scanf("%d%d",&K,&L);
	
	for (j = 0; j < K; ++j)   //第1行初始化为1,便于下面for循环i=2时的计算 
		dp[1][j] = 1;
		
	for (i = 2; i <= L; ++i)
		for (j = 0; j < K; ++j)
			for (x = 0; x < K; ++x)        
				if (x != j-1 && x!= j+1)  //左右不相邻 
				{
					dp[i][j] += dp[i-1][x]; //循环累加上一行for(..x..) 
					dp[i][j] %= 1000000007;
				}
				
	for (j = 1; j < K; ++j)   //将最后一行累加,第一列0,不统计 
	{
		sum += dp[L][j];
		sum %= 1000000007;
	}
	printf("%lld\n",sum);
	
	return 0;
} 


提交序号 姓名 试题名称 提交时间 
代码长度
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  • CPU使用 
    内存使用 
    评测详情
    106844 Analyst K好数 03-02 22:41 567B C 正确 100 15ms 1.160MB 评测详情

    转载请保留原文地址:http://blog.csdn.net/jopus/article/details/20315381

    ### 关于蓝桥杯竞赛中组分割问题的动态规划解决方案 #### 基本概念与背景 动态规划是一种高效的算法设计方法,特别适用于解决具有重叠子问题和最优子结构性质的问题。在蓝桥杯竞赛中,组分割问题是常见的考察点之一[^1]。 对于组分割问题,其核心目标通常是将一个给定组划分为若干部分,使得满足某些特定条件下的某种指标达到最优化(如最小化最大值、最大化总和等)。此类问题可以通过动态规划来有效求解。 --- #### 动态规划的核心要素 动态规划的关键在于定义状态、转移方程以及初始化边界条件: 1. **状态定义** 定义 `dp[i][k]` 表示前 `i` 个元素被分成 `k` 组后的最优解。具体含义取决于题目要求,比如可能是分组的最大值最小化或者某项代价函的最小化。 2. **状态转移方程** 对于每一段 `[j, i]` 的划分,假设当前已经计算出了前面的状态,则可以得到如下形式的转移关系: \[ dp[i][k] = \min_{j}(\max(dp[j][k-1], sum(j+1, i))) \] 这里的 `sum(j+1, i)` 是指从第 `j+1` 到第 `i` 位置之间的子组和。该公式的目的是找到一种最佳方式使整个组被合理分配至各组之中[^4]。 3. **初始条件设置** 初始化时需考虑单一分割情况以及其他特殊情况处理逻辑;例如当只有一组时直接取全部据作为结果即可。 4. **复杂度分析** 时间复杂度一般为 \(O(n^2 * k)\),空间复杂度则依据实际存储需求而有所不同,可能简化为线性级别\(O(k*n)\)或更高维度矩阵形式视具体情况调整优化策略[^2]。 --- #### 示例代码实现 (基于Java) 下面给出了一段针对类似“组分割”的典型动态规划解答模板代码片段: ```java public class ArrayPartition { public static void main(String[] args){ int n = ... ;//输入长度n int m = ... ;//目标分区量m //读入原始组data[] long[][] dp=new long[n+1][m+1]; Arrays.fill(Arrays.stream(dp).flatMapToInt(Arrays::stream).toArray(), Long.MAX_VALUE); dp[0][0]=0; for(int i=1;i<=n;i++){ for(int j=i>=m?m:i;j>0;j--){ for(int p=j-1;p<i;p++) { dp[i][j] = Math.min( dp[i][j], Math.max(dp[p][j-1], getSum(data,p+1,i)) ); } } } System.out.println(dp[n][m]); } private static long getSum(int[] data, int start, int end){ // 计算[start,end]区间的累加和 long res=0; for(int idx=start;idx<=end;idx++)res+=data[idx-1]; return res; } } ``` 此代码实现了基本框架结构并提供了简单功能演示说明如何利用双重循环遍历所有可能性从而完成最终答案获取过程[^4]。 --- ### 注意事项 需要注意的是,在实际比赛中可能会遇到更多变体版本的问题设定,因此灵活运用上述理论基础非常重要。此外还需注意边界条件判断准确性以及性能瓶颈规避等问题以免影响得分效率等方面表现不佳的情况发生。
    评论 20
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值