bzoj1026 [SCOI2009]windy数

来源:互联网 发布:网络销售靠谱吗 编辑:程序博客网 时间:2024/04/25 22:40

传送门

题目描述

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数组,f[i][j]表示保留第i位以前的部分,第i位为j的windy数的个数。
用r+1的结果减l的结果(因为实际上求的是该数-1)。
计算时要分成多种情况考虑。
本蒟蒻写的代码中f数组是将数倒着考虑的,num数组是正着考虑的,结果带来了各种问题。
当然也可以直接用字符串读入,就不用再将数分成每一位了。
详细解法见代码。

#include<cstdio>#include<cstdlib>#include<iostream>using namespace std;int l,r;int f[11][10];int num[11];inline int work(int n){    int ans=0;    while(n) n/=10,ans++;    return ans;}inline void divide(int n){    int len=work(n),t=n;    while(len) num[len--]=n%10,n/=10;}inline int workout(int n){    divide(n);    int ans=0,len=work(n);    for(int i=1;i<len;i++)      for(int j=1;j<=9;j++)        ans+=f[i][j];    for(int i=1;i<num[1];i++)      ans+=f[len][i];    for(int i=2;i<=len;i++)    {        for(int j=0;j<num[i];j++)          if(abs(j-num[i-1])>=2) ans+=f[len-i+1][j];//注意不是f[i][j]        if(abs(num[i]-num[i-1])<2) break;    }    return ans;}int main(){    scanf("%d%d",&l,&r);    for(int i=0;i<=9;i++) f[1][i]=1;    for(int i=2;i<=9;i++)      for(int j=0;j<=9;j++)        for(int k=0;k<=9;k++)          if(abs(k-j)>=2) f[i][j]+=f[i-1][k];    for(int i=1;i<=2;i++)      for(int j=0;j<=9;j++)        if(abs(i-j)>=2) f[10][i]+=f[9][j];    printf("%d",workout(r+1)-workout(l));    return 0;}
0 0
原创粉丝点击