P2657 [SCOI2009] windy 数

//URL:https://www.luogu.com.cn/problem/P2657
/*
数位dp 
1.若前面有小于目标位数字的 后面可以任意选
2.直接用记忆化搜索
3.若有前导零 后一位任意 
4.若未搜完 done==1 就是还要搜 只有done===0才可以return
f[pos][sta]:在pos位 前一位是sta的 总和 
1.若是没有限制的done==0 f[pos][pre-sta]=sum(f[pos-1][<=pre-sta-2])
2.反之done==1 就要一步步搜 pos==0 return 1
*/
/*
25 50

20

1 10

9
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string.h>
#include<queue>
#include<vector>
#include<bits/stdc++.h>
typedef long long ll;
#define ddd printf("-----------------------\n");
using namespace std;
const int maxn=1e1 +10;
const int mod=998244353;
const int inf=0x3f3f3f3f;

int f[30][12],a[30];

int dfs(int pos,int sta,int done)
{
    if(pos==0) return 1;
    if(done==0&&f[pos][sta]!=-1) return f[pos][sta];
    
    int res=0;
    int end=done? a[pos]:9;
    for(int i=0;i<=end;i++)
    {
        if(abs(i-sta)<2) continue;
        if(i==0&&sta==11) res+=dfs(pos-1,11,done&&i==end);
        else res+=dfs(pos-1,i,done&&i==end);
    }
    if(done==0) f[pos][sta]=res;
    
    return res;
}
int solve(int x)
{
    memset(f,-1,sizeof(f));
    //memset(a,0,sizeof(a));
    a[0]=0;
    
    while(x)
    {
        a[++a[0]]=x%10;
        x/=10;
    }
    return dfs(a[0],11,1);
    
}
int main()
{
    ios::sync_with_stdio(false);
    int a,b;cin>>a>>b;
    cout<<solve(b)-solve(a-1)<<'\n';
    
    return 0;
}

 

posted @ 2024-01-15 04:17  JMXZ  阅读(5)  评论(0)    收藏  举报