洛谷 P2657 [SCOI2009] windy 数(数位dp)

题目链接

数位DP板子题

数位DP知识点:

AC代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a,b,lim[15],dp[10][10];//第一维表示位数,第二维表示首数字是谁。dp表示这种请况下windy数有几个
int dfs(int pos,int pre,bool limit,bool lead){//当前位数,上个数字,是否限制大小,是否有前导零 
    if(pos==-1)
        return 1;
    if(!limit&&!lead&&dp[pos][pre]!=-1){//如果记录过,则直接返回 
        return dp[pos][pre];
    }
    int temp=0;
    int up = limit?lim[pos]:9;//更改上界 
    for(int i=0;i<=up;i++){
        if(abs(i-pre)<2&&!lead)//如果有前导0的话就不需要考虑相差大于2的情况 
            continue;
        temp+=dfs(pos-1,i,limit&&i==lim[pos],lead&&!i);
    }
    if(!limit&&!lead){//如果没有前导0且不是最高位,则保存下来便于下次查询 
        dp[pos][pre]=temp;
    }
    return temp;
} 
int solve(int a){
    int cnt=0;
    while(a>0){
        lim[cnt++]=a%10;//记录每个数位 
        a/=10;
    }
    int ans=dfs(cnt-1,0,1,1);//因为从最高位进去。故limit=1,因为最高位取值是受到限制的。lead=1,因为最高位的更高位一定为0. 
    return ans;
}
int main(){
    memset(dp,-1,sizeof(dp));//在这里初始化,方便查询 
    scanf("%d%d",&a,&b);
    printf("%d\n",solve(b)-solve(a-1));
    return 0;
}

 

posted @ 2021-03-31 22:55  mikku  阅读(72)  评论(0)    收藏  举报