传送门

Description

\(windy\)定义了一种\(windy\)数。不含前导零且相邻两个数字之差至少为\(2\)的正整数被称为\(windy\)数。\(windy\)想知道,

在\(A\)和\(B\)之间,包括\(A\)和\(B\),总共有多少个\(windy\)数?

Input

包含两个整数,\(A,B\)。

Output

一个整数

Sample Input

25 50

Sample Output

20

Hint

\(For~All:\)

\(1~\leq~A~\leq~B~\leq~2~\times~10^9\)

Solution

数位DP。

数位DP的DP状态一般含有如下参数:

1、从高到低当前填到了第几位。

2、当前这一位的数是几。

3、这一位是否等于一个上界x。一般而言,大于上界没有意义,所以可以用一个二进制表示等于或小于。

4、从最高位到这一位是否全为0

对于具体题目,需要根据要求增删状态。

对于本题而言,可以设\(f_{i,j,0/1,0/1}\)代表从高到低填到了第i位,当前这一位数字是j,否/是等于0,否/是全为0的方案数

考虑\([A,B]\)间的答案就等于小于\(B\)的答案减去小于\(A-1\)的答案。于是可以分别把\(B\)和\(A-1\)作为上界x求得答案相减。

预处理:处理出第一位所有的情况。具体的,设第一位是\(s_1\),则\(f_{1,j,0,0}=1|j<s_1\),\(f_{1,0,0,1}=1\),\(f_{1,s_1,1,0}=1\)

转移方面,这里使用刷表法刷出下一维。具体的,枚举当前是什么状态,枚举下一位的数字是谁。

直接累加小于上界且从小于上界的状态转移的答案,对于等于上界的状态,转移到等于上界的状态。注意区分小于和等于在第3维上的差异。

显然每一位全是前导零的方案数是1。对于本位置全是前导0的方案,可以更新下一位填任意位置小于上界的状态。

最后累加答案为\(ans=(\sum_{j<s_{len}}f_{len,j,0,0})+f_{len,s_{len},1,0}\)。其中len为上界x的位数。

看着发晕的话可以参考代码

Code

#include<cstdio>
#include<cstring>
#define rg register
#define ci const int
#define cl const long long int typedef long long int ll; namespace IO {
char buf[90];
} template<typename T>
inline void qr(T &x) {
char ch=getchar(),lst=' ';
while(ch>'9'||ch<'0') lst=ch,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(lst=='-') x=-x;
} template<typename T>
inline void write(T x,const char aft,const bool pt) {
if(x<0) x=-x,putchar('-');
int top=0;
do {
IO::buf[++top]=x%10+'0';
x/=10;
} while(x);
while(top) putchar(IO::buf[top--]);
if(pt) putchar(aft);
} template<typename T>
inline T mmax(const T a,const T b) {if(a>b) return a;return b;}
template<typename T>
inline T mmin(const T a,const T b) {if(a<b) return a;return b;}
template<typename T>
inline T mabs(const T a) {if(a<0) return -a;return a;} template<typename T>
inline void mswap(T &a,T &b) {
T temp=a;a=b;b=temp;
} const int maxs = 15; ll a,b;
ll frog[maxs][maxs][5][5],st[maxs]; ll dp(ll x); int main() {
qr(a);qr(b);
a=dp(a-1);memset(frog,0,sizeof frog);b=dp(b);
write(b-a,'\n',true);
return 0;
} ll dp(ll x) {
int len=0;
rg ll tx=x;
do {++len;} while(tx/=10);if(!x) len=0; //确定x的位数
for(rg int i=len;i;--i) st[i]=x%10,x/=10; //st[i]即为s数组,存储x每一位的值
for(rg int i=1;i<st[1];++i) frog[1][i][0][0]=1;
frog[1][st[1]][1][0]=frog[1][0][0][1]=1;
/*
*初始化:
*第一位填小于s[1]的数,整个数小于x前1位且无前导0的方案数
*=第一位填s[1]的数,整个数等于x前1位的方案数
*=全部填0的方案数=1
*/
for(rg int i=1;i<len;++i) {
rg int di=i+1; //下一位置
for(rg int j=0;j<10;++j) {
for(rg int k=0;k<10;++k) {
if(mabs(j-k) >= 2) { //如果这一位合法
frog[di][k][0][0]+=frog[i][j][0][0]; //这一位填k的方案数,从上一位的数小于x转移
if(k < st[di]) frog[di][k][0][0]+=frog[i][j][1][0];
//从上一位等于x的数转移到这一位小于x的答案
else if(k == st[di]) frog[di][k][1][0]+=frog[i][j][1][0];
//从上一位等于x的数转移到这一位等于x的答案
}
}
}
frog[di][0][0][1]=1; //下一位全是前导0的方案数为1
for(rg int j=1;j<10;++j) frog[di][j][0][0]+=frog[i][0][0][1];
//由这一位全是前导0可以更新下一位的不取0的所有情况。
}
ll _ans=0;
for(rg int i=0;i<10;++i) _ans+=frog[len][i][0][0];
_ans+=frog[len][st[len]][1][0];
return _ans;
}

Summary

数位dp状态的确定:

1、从高到低当前填到了第几位。

2、当前这一位的数是几。

3、这一位是否等于一个上界x。一般而言,大于上界没有意义,所以可以用一个二进制表示等于或小于。

4、从最高位到这一位是否全为0

转移细节比较多,需要留心

【数位DP】【SCOI2009】windy数的更多相关文章

  1. 数位dp——BZOJ1026 Windy数

    1026: [SCOI2009]windy数 Time Limit: 1 Sec  Memory Limit: 162 MB Description windy定义了一种windy数.不含前导零且相邻 ...

  2. [暑假集训--数位dp]UESTC250 windy数

    windy定义了一种windy数. 不含前导零且相邻两个数字之差至少为22 的正整数被称为windy数. windy想知道,在AA 和BB 之间,包括AA 和BB ,总共有多少个windy数? Inp ...

  3. bzoj 1026 [SCOI2009]windy数 数位dp

    1026: [SCOI2009]windy数 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline ...

  4. bzoj 1026 [SCOI2009]windy数(数位DP)

    1026: [SCOI2009]windy数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 4550  Solved: 2039[Submit][Sta ...

  5. BZOJ_1026_[SCOI2009]windy数_数位DP

    BZOJ_1026_[SCOI2009]windy数_数位DP 题意:windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道, 在A和B之 ...

  6. bzoj1026: [SCOI2009]windy数(数位dp)

    1026: [SCOI2009]windy数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 8203  Solved: 3687[Submit][Sta ...

  7. luogu P2657 [SCOI2009]windy数 数位dp 记忆化搜索

    题目链接 luogu P2657 [SCOI2009]windy数 题解 我有了一种所有数位dp都能用记忆话搜索水的错觉 代码 #include<cstdio> #include<a ...

  8. 2018.06.30 BZOJ1026: [SCOI2009]windy数(数位dp)

    1026: [SCOI2009]windy数 Time Limit: 1 Sec Memory Limit: 162 MB Description windy定义了一种windy数.不含前导零且相邻两 ...

  9. 1026: [SCOI2009]windy数(数位dp)

    1026: [SCOI2009]windy数 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 9016  Solved: 4085[Submit][Sta ...

  10. bzoj1026: [SCOI2009]windy数(传说你是数位DP)

    1026: [SCOI2009]windy数 题目:传送门 题解: 其实之前年少无知的时候好像A过...表示当时并不知道什么数位DP 今天回来深造一发... 其实如果对这个算法稍有了解...看到这题的 ...

随机推荐

  1. 负数取余/整除,Python和C语言的不同

    总结一句:Python中负数整除,是向负无穷取整,所以导致负数取余不对 在数学公式中,两种语言的表示算法都是一样的,都是: r=a-n*[a/n] 以上,r是余数,a是被除数,n是除数. 唯一不同点, ...

  2. Apache--Override参数详解

    1  AuthConfig  允许使用所有的权限指令,他们包括AuthDBMGroupFile AuthDBMUserFile  AuthGroupFile  AuthName AuthTypeAut ...

  3. vue 与jq 的对比

    vue.react和angular,众所周知,他们是前端框架的3个大佬.这篇主要想对比一下用vue和用jq的区别,至于和其他框架的对比,我想vue的官网说的更为详细. 我算是独自用vue写过一个小型项 ...

  4. Linux error:No space left on device

    一台Oracle数据库服务器在关机重启后,Oracle监听无法启动,提示错误 Linux error:no space left on device 提示可知:问题是出在磁盘空间不足 但是初步查看分区 ...

  5. Java静态方法,静态变量,初始化顺序

    1. 静态方法: 成员变量分为实例变量和静态变量.其中实例变量属于某一个具体的实例,必须在类实例化后才真正存在,不同的对象拥有不同的实例变量.而静态变量被该类所有的对象公有(相当于全局变量),不需要实 ...

  6. lintcode-16-带重复元素的排列

    带重复元素的排列 给出一个具有重复数字的列表,找出列表所有不同的排列. #### 样例 给出列表 [1,2,2],不同的排列有: [ [1,2,2], [2,1,2], [2,2,1] ] 挑战 使用 ...

  7. iOS- 利用UIImageView自己整了个不会说话的汤姆猫

    1.实现思路 先说说我实现它的主要思路,很简单,主要利用UIImageView连续动画播放,和按钮的点击事件,就可以完成了这么一个简单的不会说话的汤姆猫. 2.实现细节 2.1.加载本地字典里保存的本 ...

  8. 【week6】用户数

    小组名称:nice! 小组成员:李权 于淼 杨柳 刘芳芳 项目内容:约跑app alpha发布48小时以后用户数如何,是否达到预期目标,为什么,是否需要改进,如何改进(或理性估算). 首先我们的app ...

  9. dedecms 后台登录地址

    dedecms  后台登录地址 http://www.域名.com/member/index.php

  10. HASH表的实现(拉链法)

    本文的一些基本概念参考了一部分百度百科,当然只保留了最有价值的部分,代码部分完全是自己实现! 简介 哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据 ...