[SCOI2009]windy数(数位dp)

http://code.qingtengbc.com/problem/10139

搜到了结束的状态,意味着该数字本身取完是合法的。

关于不考虑前导零
比如23456,我们搜3456这个状态的时候,是以"03456"去搜索的。

windy数让你考虑相邻数位差>=2。那么比如上面的状态中存在15的合法状态,但是由于我们以前导零方式搜是015,这个0和1我们判相邻数位差的时候就会考虑进去从而认定为非法,所以有的题目需要判定这个前导零。

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=40;
int a[maxn];
int tot=0;
int dp[maxn][10];///一共pos位且上一位为j的方案数量
// ...
int dfs(int pos,int pre,bool lead,bool limit)
{
    if(pos==0) return 1;///搜到了结尾
    if(!limit&&dp[pos][pre]!=-1) return dp[pos][pre];//如果不是带有限制的情况并且上一位是pre的情况已经搜完了,直接获得
    int res=0;
    int bound=9;
    if(limit==1) bound=a[pos];
    for(int i=0;i<=bound;i++){
        //有前导0并且当前位也是前导0
        if((!i)&&lead){
            res+=dfs(pos-1,i,1,i==bound&&limit);
        }
        //有前导0但当前位不是前导零,当前位就是最高位
        else if(i&&lead){
            res+=dfs(pos-1,i,0,i==bound&&limit);
        }
        else if(abs(pre-i)>=2){
            res+=dfs(pos-1,i,0,i==bound&&limit);
        }
    }
    if(!limit&&!lead) dp[pos][pre]=res;
    return res;
}
inline int solve(int num)
{
    tot=0;
    memset(a,0,sizeof(a));
    while(num>0){
        a[++tot]=num%10;num/=10;
    }
    memset(dp,-1,sizeof(dp));
    int res=dfs(tot,0,1,1);
    return res;
}
int main()
{
    int l,r;cin>>l>>r;
    cout<<solve(r)-solve(l-1)<<endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值