BZOJ-1026: [SCOI2009]windy数 (数位DP)

 

 

1026: [SCOI2009]windy数

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 5665  Solved: 2534
[Submit][Status][Discuss]

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 。

 

Source

算法:比较基础的数位DP,详细解释程序中有

 

 1 #include <cstdio>
 2 #include <cmath>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <queue>
 6 #include <stack>
 7 #include <vector>
 8 #include <iostream>
 9 #include "algorithm"
10 using namespace std;
11 typedef long long LL;
12 const int MAX=15;
13 int f[MAX][10];
14 //f[i][j] 表示 i 位数,最高位为 j 的方案数 
15 
16 void init(){//初始化范围内的所有数 
17     int i,j,k;
18     memset(f,0,sizeof(f));
19     for (i=0;i<10;i++)
20      f[1][i]=1;
21     for (i=2;i<MAX;i++)//枚举位数 
22      for (j=0;j<10;j++)//枚举最高位 
23       for (k=0;k<10;k++)//枚举第二高位 
24        if (abs(j-k)>=2)//符合条件 
25         f[i][j]+=f[i-1][k];
26 }
27 int satistics(int x){
28     int ans(0);
29     int s[MAX]={0};
30     while (x) {s[++s[0]]=x%10;x/=10;}//数字分离 
31     s[s[0]+1]=0;
32     int i,j,k;
33     for (i=1;i<s[0];i++)
34      for (j=1;j<10;j++)//可以有前导零,所以从0开始枚举 
35       ans+=f[i][j];
36     for (j=1;j<s[s[0]];j++)
37      ans+=f[s[0]][j];
38     // 举个栗子 5963 前面已经处理了5000以前的windy数,现在开始处理剩下的963 
39     for (i=s[0]-1;i>=1;i--)
40     {for (j=0;j<s[i];j++)
41       if (abs(j-s[i+1])>=2)
42        ans+=f[i][j];
43      if (abs(s[i]-s[i+1])<2)//如果已经出现不合法的,那么就直接退出 
44       break;
45     }
46     return ans;
47 }
48 int main(){
49     init();int i,j;
50     int x,y;
51     scanf("%d%d",&x,&y);
52     printf("%d",satistics(y+1)-satistics(x));
53     return 0;
54 }

 

posted @ 2016-07-30 16:04  lonely_OIer  阅读(118)  评论(0编辑  收藏  举报