蓝桥水题_算法训练 K好数
2018-01-05 16:18
309 查看
题目看了很久,都没看懂为什么“K = 4,L = 2的时候,所有K好数为11、13、20、22、30、31、33 共7个”,那“00、02、03”去哪了,问人才知道,这0开头的不算自然数。。。,因为自然数是0,2,3一位,不是两位,囧
一开始没想到是用动态规划,想的是用找规律或者暴力枚举,搞了很久没想出来思路,打开锦囊知道是DP,不过还是没思路。
网上看了别人的代码,琢磨了一下,其实原理就是以1位数作为基础,一步一步去推剩下的K位数包含几个好数
K = 4,L = 3时,比如dp[2][3]代表以3结尾的2位数中(K=4进制)有几个好数
则状态转移方程为:
dp[i][j] += dp[i-1][x] (未考虑取余)
第一步,将1到K-1结尾的一位数的包含好数值设为1(注意不从0开始,因为00,01不算自然数),因为1,2,3天然算好数
第二部,所以dp(2,1) = dp(1,1) + dp(1,3) ,因为x不能等于 0 和 2,这样一直带入
......
最后一步,将dp(L,0)到dp(L,3)累加,即最后的结果(未考虑取余)
代码:
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <stack>
#include <list>
#include <algorithm>
using namespace std;
#define MAX 101
#define MOD_NUM 1000000007
//dp(动态规划)数组的第一个数为位数,第二个数K进制
//(这也是一个坑点,题目应该是K < 10^6,但实测开不了那么大,不过不影响提交)
//K = 4,L = 2时,dp[2][3]代表以3结尾的2位数中(K=4进制)有几个好数
unsigned long long dp[MAX][200000];
int main() {
unsigned long long K = 0,L = 0;
cin>>K>>L;
for(int i = 1 ; i < K ; ++i) {
//初始化,这个想了很久,这题是从一位数开始考虑的
//之所以不从0开始,是因为类似 00,01,002这些数不算自然数,
//其他的数比如1、22、333这些必是好数,所以在1位时,1,2,3这些数作为基础
dp[1][i] = 1;
// printf("dp[1][%d] = 1;\n",i);
}
// cout<<endl;
//这里因为提交的时候L写成K卡了好久,一直90分,囧
for(int i = 2 ; i <= L ; ++i) {
for(unsigned long long j = 0 ; j < K ; ++j) {
for(unsigned long long x = 0 ; x < K ; ++x) {
//题目,任意的相邻的两位都不是相邻的数字
if(x!=j-1 && x!= j+1) {
//状态转移方程,这题的核心
//这里不能用+=,只能一步一步的取余,且必须要提前取余,降低数字大小
//这里的原理建议自己拿出纸笔,自己算
//比如:dp(2,0) = dp(1,0) +dp(1,1) +dp(1,3)
//因为 j = 0 , 则x不能相邻,即等于-1或1
//同理:dp(2,1) = dp(1,1,) + dp(1,3) ,因为x不能等于 0 和 2
dp[i][j] = (dp[i][j]+dp[i-1][x])%MOD_NUM;
// printf("dp[%d][%d] = (dp[%d][%d]+dp[%d-1][%d])%MOD_NUM = %d;\n",i,j,i,j,i,x,dp[i][j]);
}
}
}
}
// cout<<endl;
unsigned long long ans = 0;
for(int i = 0 ; i < K ; ++i) {
//把最高长度位的全加在一块
ans = (ans+dp[L][i]) %MOD_NUM;
// printf("ans = (ans+dp[%d][%d]) %MOD_NUM = %d ;\n",L,i,ans);
}
cout<<ans;
return 0;
}
建议把注释的printf解掉,看看调试过程
比如K = 4,L = 3时,
另外就是取余的问题,必须每一步都要取余,不然会出去超出大小的问题
原题:
问题描述
如果一个自然数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
一开始没想到是用动态规划,想的是用找规律或者暴力枚举,搞了很久没想出来思路,打开锦囊知道是DP,不过还是没思路。
网上看了别人的代码,琢磨了一下,其实原理就是以1位数作为基础,一步一步去推剩下的K位数包含几个好数
K = 4,L = 3时,比如dp[2][3]代表以3结尾的2位数中(K=4进制)有几个好数
则状态转移方程为:
dp[i][j] += dp[i-1][x] (未考虑取余)
第一步,将1到K-1结尾的一位数的包含好数值设为1(注意不从0开始,因为00,01不算自然数),因为1,2,3天然算好数
第二部,所以dp(2,1) = dp(1,1) + dp(1,3) ,因为x不能等于 0 和 2,这样一直带入
......
最后一步,将dp(L,0)到dp(L,3)累加,即最后的结果(未考虑取余)
代码:
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <stack>
#include <list>
#include <algorithm>
using namespace std;
#define MAX 101
#define MOD_NUM 1000000007
//dp(动态规划)数组的第一个数为位数,第二个数K进制
//(这也是一个坑点,题目应该是K < 10^6,但实测开不了那么大,不过不影响提交)
//K = 4,L = 2时,dp[2][3]代表以3结尾的2位数中(K=4进制)有几个好数
unsigned long long dp[MAX][200000];
int main() {
unsigned long long K = 0,L = 0;
cin>>K>>L;
for(int i = 1 ; i < K ; ++i) {
//初始化,这个想了很久,这题是从一位数开始考虑的
//之所以不从0开始,是因为类似 00,01,002这些数不算自然数,
//其他的数比如1、22、333这些必是好数,所以在1位时,1,2,3这些数作为基础
dp[1][i] = 1;
// printf("dp[1][%d] = 1;\n",i);
}
// cout<<endl;
//这里因为提交的时候L写成K卡了好久,一直90分,囧
for(int i = 2 ; i <= L ; ++i) {
for(unsigned long long j = 0 ; j < K ; ++j) {
for(unsigned long long x = 0 ; x < K ; ++x) {
//题目,任意的相邻的两位都不是相邻的数字
if(x!=j-1 && x!= j+1) {
//状态转移方程,这题的核心
//这里不能用+=,只能一步一步的取余,且必须要提前取余,降低数字大小
//这里的原理建议自己拿出纸笔,自己算
//比如:dp(2,0) = dp(1,0) +dp(1,1) +dp(1,3)
//因为 j = 0 , 则x不能相邻,即等于-1或1
//同理:dp(2,1) = dp(1,1,) + dp(1,3) ,因为x不能等于 0 和 2
dp[i][j] = (dp[i][j]+dp[i-1][x])%MOD_NUM;
// printf("dp[%d][%d] = (dp[%d][%d]+dp[%d-1][%d])%MOD_NUM = %d;\n",i,j,i,j,i,x,dp[i][j]);
}
}
}
}
// cout<<endl;
unsigned long long ans = 0;
for(int i = 0 ; i < K ; ++i) {
//把最高长度位的全加在一块
ans = (ans+dp[L][i]) %MOD_NUM;
// printf("ans = (ans+dp[%d][%d]) %MOD_NUM = %d ;\n",L,i,ans);
}
cout<<ans;
return 0;
}
建议把注释的printf解掉,看看调试过程
比如K = 4,L = 3时,
另外就是取余的问题,必须每一步都要取余,不然会出去超出大小的问题
原题:
问题描述
如果一个自然数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
相关文章推荐
- 蓝桥水题_ 算法训练 最大最小公倍数
- 蓝桥 算法训练 区间k大数查询(sort函数)
- 算法训练 奇偶判断(水题)
- 算法训练 送分啦 【史上最水题】
- 蓝桥 算法训练 区间k大数查询(Java)
- 蓝桥-分糖果(算法训练)
- 算法训练 进制转换(水题)
- 【蓝桥】 算法训练 最大最小公倍数
- 蓝桥 算法训练 2的次幂表示 递归
- 蓝桥网 算法训练 传球游戏
- 蓝桥杯 算法训练 区间k大数查询(水题)
- 蓝桥 练习系统 算法训练 学做菜
- 【蓝桥】 算法训练 K好数
- 蓝桥 算法训练 ALGO-116 最大的算式
- 蓝桥-分糖果(算法训练)
- 蓝桥杯 算法训练 星际交流(水题)
- 蓝桥杯 算法训练 摆动序列 搜索水题
- 算法训练 大小写判断 (水题)
- 蓝桥 算法训练 最短路
- 蓝桥算法训练 未名湖边的烦恼