P2657 [SCOI2009] windy 数 数位DP好题

P2657 [SCOI2009] windy 数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

数位DP好题

主要问题是:不含前导零且相邻两个数字之差至少为 2

solution:

现在枚举到了第 i 位

1.如果第 i-1 位是正常的数,不是前导0,那么只要 (第 i 位的数) - (第 i-1 位的数) ≥  2,便符合题意

2.如果第 i-1位是前导0,显然第 i 位 可以取 0~9 之间所有的数,

根据上面两点,当 第 i-1 位是正常的数,不是前导0  并且  (第 i 位的数) - (第 i-1 位的数) <  2 时,便是不符合条件的情况

if(abs(last-i)<2&&zero==0) continue;

 

DP维度:pos,limit,zero,上一位数(last)

Code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define pb push_back   //vector函数
#define popb pop_back  //vector函数
#define fi first
#define se second
const int N=20;
//const int M=;
//const int inf=0x3f3f3f3f;     //一般为int赋最大值,不用于memset中
//const ll INF=0x3ffffffffffff; //一般为ll赋最大值,不用于memset中
int T,n,len,a[N],dp[N][N][2][2];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
int dfs(int pos,int last,bool lim,bool zero)
{
    if(pos>len) return 1;
    if(dp[pos][last][lim][zero]!=-1) return dp[pos][last][lim][zero];
    int res=0,num=lim?a[pos]:9;
    for(int i=0;i<=num;i++)
    {
        if(abs(last-i)<2&&zero==0) continue;
        res+=dfs(pos+1,i,lim && i==num,zero && i==0 );
    }
    return dp[pos][last][lim][zero]=res; 
} 
int solve(int x)
{
    len=0;
    memset(dp,-1,sizeof(dp));
    for(;x;x/=10) a[++len]=x%10;
    reverse(a+1,a+len+1);
    return dfs(1,0,1,1);
}
int main()
{
//    freopen("","r",stdin);
//    freopen("","w",stdout);    
    int l=read(),r=read();
    printf("%d\n",solve(r)-solve(l-1));
    return 0;
}

 

posted @ 2023-01-24 16:08  QAQ啥也不会  阅读(14)  评论(0编辑  收藏  举报