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

解题报告:

  第一道完全弄懂的数位DP题,好好总结一下。

  首先预处理,用f[i][j]表示i位数中最高位为j的windy数的个数,可以很快处理出来。

  我们考虑[a,b]区间完全可以转换为[1,b]-[1,a-1],所以我们先讨论如何统计[1,b]中windy数的个数。

  首先我们对于这个区间内的所有数分一分类,(设b位数为len,并且在ABCDEF这个6位数中,A为第len位,F为第1位,a数组表示每一位数是多少,例如a[len]为最高位数字)

  第一类 达不到len位的所有情况,那么不足的位数补0,所以我们可以直接对于第len-1到第1位放1到9的任何数的f都算一遍所有windy数,加入答案(就是∑f[i][j],1<=i<len,1<=j<=9)

  第二类 达到len位但最高位取不到极限的所有情况,那么我们直接把f[len][i],1<=i<a[len]加入ans即可。

  第三类 达到len为且最高位取极限的所有情况,从len-1到1一路累加答案,枚举到第i位时,默认为i+1到len都取得是极限,也就是说,假如一个数962753,我们已经算完了不足6位和有6位但是最高位小于等于9的所有答案,我们首先令此时最高位为9,然后考虑次高位能够选什么,满足windy数的性质就把其f加入答案。这一步操作相当于默认每一个处理完的位都是取最大值了。要注意一点,当我处理到某位发现当前位与前一位已经不满足windy数了,那么后面无论怎样都不可能满足性质,所以直接break就可以了。 

  

 

 1 //It is made by jump~
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 #ifdef WIN32   
14 #define OT "%I64d"
15 #else
16 #define OT "%lld"
17 #endif
18 using namespace std;
19 typedef long long LL;
20 int ans,len;
21 int a[12];
22 int f[12][12];//f[i][j]表示i位数中最高位为j的方案数
23 
24 inline int getint()
25 {
26        int w=0,q=0;
27        char c=getchar();
28        while((c<'0' || c>'9') && c!='-') c=getchar();
29        if (c=='-')  q=1, c=getchar();
30        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
31        return q ? -w : w;
32 }
33 
34 inline void Init(){
35     for(int i=0;i<=9;i++) f[1][i]=1;//记得算0
36     for(int i=2;i<=10;i++) 
37     for(int j=0;j<=9;j++)
38         for(int k=0;k<=9;k++)
39         if(abs(j-k)>=2) f[i][j]+=f[i-1][k];    
40 }
41 
42 inline int solve(int x){
43     if(x<=0) return 0;
44     ans=0; len=0; while(x) { a[++len]=x%10; x/=10; }
45     //part 1 达不到len位的所有情况
46     for(int i=len-1;i;i--) for(int j=1;j<=9;j++) ans+=f[i][j];//前面位数全部取0,即高位没有数
47     //part 2 达到len位但最高位取不到极限的所有情况
48     for(int i=1;i<a[len];i++) ans+=f[len][i];//计算最高位达不到极限的所有情况,显然都可行
49     //part 3 达到len为且最高位取极限的所有情况,从len-1到1一路累加答案,枚举到第i位时,默认为i+1到len都取得是极限
50     for(int i=len-1;i;i--) {//计算每一位取极限的值,一路往下累加答案
51     for(int j=0;j<a[i];j++) if(abs(a[i+1]-j)>=2) ans+=f[i][j];//似乎可以取0
52     if(abs(a[i+1]-a[i])<2) break;//高位都取极限已经不满足windy数性质,直接break
53     }
54     return ans;
55 }
56 
57 inline void work(){
58     int sx=getint(),sy=getint();
59     Init();
60     printf("%d",solve(sy+1)-solve(sx));
61 }
62 
63 int main()
64 {
65   work();
66   return 0;
67 }

 

posted @ 2016-08-13 18:05  ljh_2000  阅读(429)  评论(0编辑  收藏  举报