洛谷 P2657 [SCOI2009]windy数 解题报告

P2657 [SCOI2009]windy数

题目描述

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

\(A\)\(B\)之间,包括\(A\)\(B\),总共有多少个\(\tt{windy}\)数?

输入输出格式

输入格式:

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

输出格式:

一个整数

说明

\(100\%\)的数据,满足 \(1 \le A \le B \le 2000000000\)


跟着咕咕日报了解了一下套路的数位\(\tt{DP}\)的写法,发现之前自己\(\tt{yy}\)的太\(\tt{naive}\)

思路是把前导\(0\)和高位限制放到记搜里面做参数直接解决。


Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
int dp[12][10],a[12];
int dfs(int dep,int pre,int lead,int limit)//第几位,上一位的数字,前导0,高位是否有限制
{
    if(~dp[dep][pre]&&!lead&&(!limit||!dep)) return dp[dep][pre];
    if(dep==0) return 0;
    int res=limit?a[dep]:9,ret=0;
    for(int i=0;i<=res;i++)
    {
        if(!lead&&abs(pre-i)<2) continue;
        if(!i&&lead) ret+=dfs(dep-1,i,lead,limit&i==res);
        //选0且有前导0,仍然有
        if(i&&lead) ret+=dfs(dep-1,i,!lead,limit&i==res);
        //选0且无前导0,没了
        if(!lead) ret+=dfs(dep-1,i,lead,limit&i==res);
        //无前导0
    }
    if(!limit&&!lead) dp[dep][pre]=ret;
    return ret;
}
int solve(int n)
{
    if(!n) return 0;
    int cnt=0;
    for(int i=1;n;i++) a[++cnt]=n%10,n/=10;
    return dfs(cnt,0,1,1);
}
int main()
{
    int a,b;
    memset(dp,-1,sizeof(dp));
    for(int i=0;i<=9;i++) dp[0][i]=1;
    scanf("%d%d",&a,&b);
    printf("%d\n",solve(b)-solve(a-1));
    return 0;
}

2018.11.6

转载于:https://www.cnblogs.com/butterflydew/p/9919231.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值