[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;
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/120522501