数位动态规划:Windy数
题目描述
Windy 定义了一种 Windy 数:不含前导零且相邻两个数字之差至少为 2 的正整数被称为 Windy 数。
Windy 想知道,在 A 和 B 之间,包括 A 和 B,总共有多少个 Windy 数?
输入格式
共一行,包含两个整数 A 和 B。
输出格式
输出一个整数,表示答案。
数据范围
1≤A≤B≤2×1091≤A≤B≤2×10^91≤A≤B≤2×109
输入样例1
1 10
输出样例1
9
输入样例2
25 50
输出样例2
20
算法思想
根据题目描述求一个区间 [A,B][A,B][A,B]中、有多少个满足不含前导零且相邻两个数字之差至少为 2的数字个数 。用数位DP的思想进行分析,例如求区间 [A,B][A,B][A,B]中符合条件的数的个数:
- 实现函数
dp(n)
求区间 [1,n][1,n][1,n]中符合条件的数的个数 dp(B) - dp(A - 1)
求区间 [A,B][A,B][A,B]中符合条件的数的个数
dp(n)
可以用分类谈论的方法进行计算。在不能超过n
的情况下,从最高位开始向下枚举数n
的每一位a[i]
,计算出区间[1−n][1-n][1−n]所有符合条件的方案。
如果从集合划分的角度进行分析,可以将所有分类用一棵二叉树表示出来。如下图所示:
- 左侧分支表示所有符合条件的数中第
i
位小于a[i]
的情况,即0−a[i]−10-a[i] - 10−a[i]−1。此时,剩余i
位的数字任意取都不会超过n
,因此这一类的方案可以通过预先处理出i
位数字且最高位不超过a[i] - 1
的方案数(相邻两个数字之差至少为 2),然后进行累加即可。 - 右侧分支表示所有符合条件的数中第
i
位等于a[i]
的情况,此时继续向下分类讨论即可。 - 最后一位
a[0]
单独处理,如果能走到最右侧结点a[0]
,说明数字n
也是满足条件的,此时总方案数增加1
。
注意:对含前导零的数字需要特殊处理,例如137是符合要求的,但是0137就不符合要求了,因此对于位数比n
少的数字需要特殊处理。
算法实现
- 预处理出
f[i][j]
,表示有i
位数字且最高位为j
的数字集合中,相邻两个数字之差至少为 2的方案数。状态计算:f[i][j]=∑f[i−1][k]f[i][j] = \sum{ f[i - 1][k] }f[i][j]=∑f[i−1][k],其中 ∣j−k∣≥2\vert j-k\vert\ge2∣j−k∣≥2 - 预处理出数字
n
的每一位a[i]
- 从高位到低位枚举,累加每一位上符合条件的方案数。
- 累加位数比
n
少的数字且满足要求的方案。
代码实现
#include <iostream>
#include <vector>
using namespace std;
const int N = 11;
//f[i][j]表示i位数且最高位为j时的Windy数的个数
int f[N][N];
void init()
{//初始化位数为1时的状态for(int i = 0; i <= 9; i ++) f[1][i] = 1;//状态计算for(int i = 2; i < N; i ++)for(int j = 0; j <= 9; j ++){for(int k = 0; k <= 9; k ++)if(abs(j - k) >= 2) f[i][j] += f[i - 1][k];}
}int dp(int n)
{//n为0时,方案数为0if(!n) return 0;vector<int> a;while(n) a.push_back(n % 10), n /= 10;//注意这里last表示上一位数字,初始化为-2,保证最高位为1时也满足条件int res = 0, last = -2;for(int i = a.size() - 1; i >= 0; i --){int x = a[i];//累加左侧分支的情况//如果i是最高位,则j从1开始枚举//否则j从0开始枚举for(int j = i == a.size() - 1; j < x; j ++){if(abs(j - last) >= 2)res += f[i + 1][j];}//没有右侧分支if(abs(x - last) < 2) break;last = x;if(!i) res ++;}// 特殊处理有前导零的数,即位数小于n的windy数for (int i = 1; i < a.size(); i ++ )for (int j = 1; j <= 9; j ++ )res += f[i][j];return res;
}int main()
{init();int a, b;cin >> a >> b;cout << dp(b) - dp(a - 1) << endl;return 0;
}
数位动态规划:Windy数相关推荐
- 数位DP --Windy数
满足一下条件的数字称为windy数 不考虑前导0,所有相邻的两个数字的差至少为2. 求出任意区间内的所有windy数 思路:dp[i][j]表示所有长度为 i 的数字以 j 开头的windy数的个数. ...
- windy数(数位dp)
1. 问题描述: windy 定义了一种 windy 数.不含前导零且相邻两个数字之差至少为 2 的正整数被称为 windy 数. windy 想知道,在 A 和 B 之间,包括 A 和 B,总共有多 ...
- bzoj 1026: [SCOI2009]windy数 数位DP算法笔记
数位DP入门题之一 也是我所做的第一道数位DP题目 (其实很久以前就遇到过 感觉实现太难没写) 数位DP题目貌似多半是问从L到R内有多少个数满足某些限制条件 只要出题人不刻意去卡多一个$log$什么的 ...
- uestc 250 windy数(数位dp)
题意:不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? 思路:数位dp #include<iostream ...
- 【bzoj1026】[SCOI2009]windy数 数位dp
题目描述 windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? 输入 包含两个整数 ...
- BZOJ1026 [SCOI2009]windy数 数位dp
欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1026 题目概括 求区间[A,B]中有多少数满足下面的条件. 条件:该数相邻两位之差不小于2. 题解 ...
- 【BZOJ1026】windy数,数位DP
Time:2016.08.14 Author:xiaoyimi 转载注明出处谢谢 思路: 依旧蛋疼的数位DP f[i][j]表示有i位,且最高位为j的windy数个数 转移方程比较好写 关键是具体求值 ...
- 洛谷2657 windy数(数位DP)
传送门 [题目分析] 数位DP经典题了. 考虑直接统计R内的windy数和L-1内的windy数,两者相减即为L~R之间的windy数. 考虑DP,记录当前位以及上一位所填的数,当前是否前面为前导零, ...
- AcWing1083. Windy数(数位DP)题解
题目传送门 题目描述 Windy 定义了一种 Windy 数:不含前导零且相邻两个数字之差至少为 2 的正整数被称为 Windy 数. Windy 想知道,在 A 和 B 之间,包括 A 和 B,总共 ...
最新文章
- 头条面试官:NIO 是不是就是I/O多路复用?我:不是
- Java、Android注解代码生成(ButterKnife原理、ViewBinding)
- 0046算法笔记——【随机化算法】舍伍德随机化思想解决跳跃表问题
- 【Linux】33. shell脚本 递归删除空目录
- 在pycharm创建scrapy项目
- Sqoop2开启Kerberos安全模式
- 关于scanf 函数,你很少了解的“秘密”
- Volley的原理解析
- SOLARIS UFS文件系统解析
- root用户改动普通用户文件
- php隐藏json数据,PHP调用出json后出来的数目字 想隐藏掉 50份求高手帮忙下
- JDK安装包和Mysql安装包整理
- spyder python下载_spyder中文版下载-spyder pythonv4.1.3 官方最新版下载__飞翔下载
- 编写谷歌浏览器插件入门
- 腾讯的星星海服务器芯片,腾讯云星星海重磅发布两款自研新品 打造软硬一体云计算基础设施...
- ionic介绍以及ionic环境搭建
- 平面设计完全手册_什么是平面设计,做平面设计都要了解哪些基础知识点?
- mysql独立开发_TickyCMS: TickyCMS是由罗敏贵独自开发的一款基于PHP+Mysql架构的轻量级开源内容管理系统。...
- 基于cocos2d-x引擎的游戏框架设计【转载】
- java电影院购票系统概况_电影院售票管理系统