P2657 [SCOI2009]windy数(数位dp)

时间:2019-11-08
本文章向大家介绍P2657 [SCOI2009]windy数(数位dp),主要包括P2657 [SCOI2009]windy数(数位dp)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题面仍然非常亲民:

windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?

这道题跟数字计数有点差别,参数比较少,传三个参数下去就行:


len:当前搜索剩余的长度
last:上一位数字是什么
up:前面是否有数字达到了枚举上限

上一位数字的初始值传一个-2进去即可
注意样例当中0这个数字不合法,全0是不可以接受的
返回答案和记忆化的时候要注意这一点

枚举方向仍然是从右向左
如果长度为0返回1即可
并且要保证任意两位绝对值之差大于等于2

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=25;

ll a,b;
int dp[N][N],num[N];

int dfs(int len,int last,int up)
//from right to left
{
    if(len==0) return 1;
    if(!up&&last>=0&&dp[len][last]!=-1)
        return dp[len][last];
    int p,cnt=0,mx=(up?num[len]:9);
    for(int i=0;i<=mx;++i)
    {
        if(abs(i-last)<2) continue;
        if(i==0&&last==-2) p=-2;
        else p=i;
        cnt+=dfs(len-1,p,up&&i==mx);
    }
    if(!up&&last>=0) dp[len][last]=cnt;
    return cnt;
}

void gao()
{
    int k=0;
    a--;
    while(a)
    {
        num[++k]=a%10;
        //start from 1
        a/=10;
    }
    memset(dp,-1,sizeof(dp));
    int left=dfs(k,-2,1);
    k=0;
    while(b)
    {
        num[++k]=b%10;
        b/=10;
    }
    memset(dp,-1,sizeof(dp));
    int right=dfs(k,-2,1);
    printf("%d\n",right-left);
}

int main()
{
    scanf("%lld%lld",&a,&b);
    gao();
    return 0;
}

原文地址:https://www.cnblogs.com/oneman233/p/11821144.html