P2657 [SCOI2009]windy数 数位dp

数位dp之前完全没接触过,所以NOIP之前搞一下。数位dp就是一种dp,emm……用来求解区间[L,R]内满足某个性质的数的个数,且这个性质与数的大小无关

在这道题中,dp[i][j]代表考虑了i位前一位为j,然后进行转移就好。主要是需要考虑前导零和前一位是否为极限。

题干:

windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,在A和B之间,包括A和B,总共有多少个windy数?
输入输出格式
输入格式:
包含两个整数,A B。
输出格式:
一个整数
输入输出样例
输入样例#1: 复制
1 10
输出样例#1: 复制
9
输入样例#2: 复制
25 50
输出样例#2: 复制
20

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(register int i = a;i <= n;i++)
#define lv(i,a,n) for(register int i = a;i >= n;i--)
#define clean(a) memset(a,0,sizeof(a))
const int INF = 1 << 30;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
        if(c == '-') op = 1;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
        x = x * 10 + c - '0';
    if(op) x = -x;
}
template <class T>
void write(T x)
{
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}
int dp[15][15],num[15],a,b;
int dfs(int len,int lst,bool sx,bool qd)
{
    if(len == 0) return 1;
    if(!qd && !sx && dp[len][lst] != -1)
    {
        return dp[len][lst];
    }
    int p,cnt = 0,maxx = (sx ? num[len] : 9);
    for(int i = 0;i <= maxx;i++)
    {
        if(abs(i - lst) < 2) continue;
        p = i;
        if(qd && i == 0) p = -233;
        cnt += dfs(len - 1,p,sx && (i == maxx),(p == -233));
    }
    if(!sx && !qd) dp[len][lst] = cnt;
    return cnt;
}
int solve(int x)
{
    int k = 0;
    while(x)
    {
        num[++k] = x % 10;
        x /= 10;
    }
    memset(dp,-1,sizeof(dp));
    return dfs(k,-233,true,true);
}
int main()
{
    read(a);read(b);
    printf("%d\n",solve(b) - solve(a - 1));
    return 0;
}

 

posted @ 2018-10-28 19:13  DukeLv  阅读(215)  评论(0编辑  收藏  举报