BZOJ1026: [SCOI2009]windy数

Posted mt-li

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ1026: [SCOI2009]windy数相关的知识,希望对你有一定的参考价值。

Description

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

Input

  包含两个整数,A B。

Output

  一个整数

Sample Input

【输入样例一】
1 10
【输入样例二】
25 50

Sample Output

【输出样例一】
9
【输出样例二】
20

HINT

【数据规模和约定】

100%的数据,满足 1 <= A <= B <= 2000000000

 

题目传送门

话说博客园这个链接有点难看。。。

换了个新环境,就学点新东西吧——数位DP

第一次做这种题还是很难搞的,%一发题解吧,没题解不能活系列

我们设f[i][j]代表i位,最高为j的数有多少是Windy数,那么我都能想到方程:f[i][j]=Sigma(f[i-1][k])(abs(k-j)>=2)

但是我们要求的是数啊,那么就得拆,拆开之后,对于每一位进行记录即可

代码如下(感觉代码讲的比我讲的清楚):

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
using namespace std;
int f[20][20],a[110000];
typedef long long ll;
void dp()
{
    for(int i=0;i<=9;i++)f[1][i]=1;
    for(int i=2;i<=12;i++)
        for(int j=0;j<=9;j++)
            for(int k=0;k<=9;k++)
                if(abs(j-k)>=2) f[i][j]+=f[i-1][k];
}
ll get_a(ll x)
{
    ll len=0;
    while(x)
    {
        a[++len]=x%10;
        x/=10;
    }
    return len;
}
ll findans(ll len)
{
    ll ans=0;
    for(int i=1;i<len;i++)
        for(int j=1;j<=9;j++)ans+=f[i][j];
    for(int i=1;i<a[len];i++)
        ans+=f[len][i];
    for(int i=len-1;i>=1;i--)
    {
        for(int j=0;j<a[i];j++)
        if(abs(a[i+1]-j)>=2)ans+=f[i][j];
        if(abs(a[i+1]-a[i])<2)break;
    }
    return ans;
}
int main()
{
    memset(f,0,sizeof(f));
    int x,y;
    scanf("%d%d",&x,&y);
    if(x>y){int tt=x;x=y;y=tt;}
    dp();
    ll lena=get_a(x),ansa=findans(lena);
    ll lenb=get_a(++y),ansb=findans(lenb);
    printf("%lld\n",ansb-ansa);
    return 0;
}

by_lmy

以上是关于BZOJ1026: [SCOI2009]windy数的主要内容,如果未能解决你的问题,请参考以下文章

[bzoj1026][SCOI2009]windy数

[BZOJ1026][SCOI2009]windy数

bzoj1026 [SCOI2009]windy数

BZOJ 1026 [SCOI2009]windy数

BZOJ 1026: [SCOI2009]windy数

bzoj1026: [SCOI2009]windy数(数位dp)