[SCOI2009]windy数(数位DP)

题目描述

windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,

在A和B之间,包括A和B,总共有多少个windy数?

输入输出格式

输入格式:

包含两个整数,A B。

输出格式:

一个整数

思路:

数位DP模板

先预处理每一个长度有多少个windy数

然后分别处理两个比边界数小的windy数有几个(类似前缀和)

怎么处理呢?

比他们位数小的,加起来就好

位数一样的,则每一位考虑

当前位与i+1位的差的绝对值大于等于2是就加上

否则跳出

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define rii register int i
#define rij register int j
#define rik register int k
using namespace std;
long long dp[15][15],l,r,every[15];
void ycl()
{
    for(rii=0;i<=9;i++)
    {
        dp[1][i]=1;
    }
    for(rii=2;i<=14;i++)
    {
        for(rij=0;j<=9;j++)
        {
            for(rik=0;k<=9;k++)
            {
                if(abs(j-k)>=2)
                {
                    dp[i][j]+=dp[i-1][k];
                }
            }
        }
    }
}
long long da(long long an)
{
    long long ans=0;
    memset(every,0,sizeof(every));
    int length=0;
    while(an)
    {
        length++;
        every[length]=an%10;
        an/=10;
    }
    for(rii=1;i<=length-1;i++)
    {
        for(rij=1;j<=9;j++)
        {
            ans+=dp[i][j];
        }
    }
    for(rii=1;i<=every[length]-1;i++)
    {
        ans+=dp[length][i];
    }
    for(rii=length-1;i>=1;i--)
    {
        for(rij=0;j<=every[i]-1;j++)
        {
            if(abs(j-every[i+1])>=2)
            {
                ans+=dp[i][j];
            }
        } 
        if(abs(every[i+1]-every[i])<2)
        {
            break;
        }
    }
    return ans;
}
int main()
{
    scanf("%lld%lld",&l,&r);
    ycl();
    long long ans=da(r+1);
    ans-=da(l);
    cout<<ans;
}

猜你喜欢

转载自www.cnblogs.com/ztz11/p/9403291.html