[SCOI2009]windy数

题目描述

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

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

输入输出格式

输入格式:

包含两个整数,A B。

输出格式:

一个整数

思路

1.DP到第几位(ws),维护方法,开始时设为上限数的位数,然后每次向下枚举时-1s,当ws为0时输出sum并且退出枚举即可。

2.DP中对获得的结果的记录(sum),维护方法,开始时设为0,当ws为1时判断此数是否为0,不是的话就+1s

3.前导零(zero),维护方法,开始时设为0(有前导零),后面枚举时当当前位置不为0或枚举当前位前前导零即不为0时设为1(无前导零),其余时刻设为0即可。

4,上一位数字(pr),维护方法,开始时设为0,后面直接传下去即可。

5,枚举上限(rua)维护方法,这个没什么说的,如果枚举当前位前就没有达到上限或者是枚举的数字不是这一位上限时设为0(未达到上限),其余设为1(达到上限)即可。

顺便强调一点,memset一定要在每次DP前都要做,不做的话会爆零。

代码

#include <cstdio>
#include <cstdlib>

int num[2][11];
int iEnd[2];

void GetNum(int x, int out[], int& sz)
{
    if (x == 0)
    {
        sz = 1;
        return;
    }
    int temp(x);
    sz = 0;
    while (temp)
    {
        temp /= 10;
        ++sz;
    }
    for (int i(0); i != sz; ++i)
    {
        out[i] = x % 10;
        x /= 10;
    }
    for (int i(0); i != sz / 2; ++i)
    {
        out[i] ^= out[sz - i - 1] ^= out[i] ^= out[sz - i - 1];
    }
}

int a, b;

bool bVis[11][11][2];
int dp[11][11][2];

inline int min(int a, int b) { return a < b ? a : b; }
inline int max(int a, int b) { return a > b ? a : b; }
inline int abs(int a) { return a < 0 ? -a : a; }

int dfs(int front, int pos, bool limit, bool forward_zero, int *num)
{
    if (!limit && bVis[front][pos][forward_zero]) return dp[front][pos][forward_zero];
    if (pos == 0) return 1;
    if (limit)
    {
        int ret(0);
        for (int i(0); i < num[0]; ++i)
        {
            if (abs(i - front) >= 2 || forward_zero)
                ret += dfs(i, pos - 1, false, (forward_zero & !i), num + 1);
        }
        if (abs(num[0] - front) >= 2 || forward_zero) ret += dfs(num[0], pos - 1, true, (forward_zero & !num[0]), num + 1);
        return ret;
    }
    else
    {
        bVis[front][pos][forward_zero] = true;
        int& state(dp[front][pos][forward_zero]);
        for (int i(0); i <= 9; ++i)
        {
            if (abs(i - front) >= 2 || forward_zero)
                state += dfs(i, pos - 1, false, (forward_zero & !i), num + 1);
        }
        return state;
    }
}

int main()
{
    scanf("%d%d", &a, &b);
    --a;
    GetNum(a, num[0], iEnd[0]);
    GetNum(b, num[1], iEnd[1]);
    int front(dfs(0, iEnd[0], true, true, num[0]));
    int last(dfs(0, iEnd[1], true, true, num[1]));
    printf("%d\n", last - front);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值