山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

bzoj 1026 [SCOI2009]windy数(数位DP)

 

1026: [SCOI2009]windy数

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 4550  Solved: 2039
[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。

       设f[i][j]表示i位数且最高位为j的数中windy数的个数。则有转移式:

              f[i][j]=sigma{ f[i-1][k] } ( | j-k |>=2 )

       统计:长度比len小的 -> 长度为len最高位比b[len]小的 -> 最高位为b[len],统计方法见代码。

       需要注意的是最后一项统计时,如果枚举过程中发现n不满足windy数则不再枚举,另外还需要注意n的计入与否。

 

【代码】

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 
 5 const int N = 15;
 6 
 7 int f[N][N],b[N];
 8 
 9 void init() {
10     for(int i=0;i<10;i++) f[1][i]=1;
11     for(int i=2;i<=10;i++)
12         for(int j=0;j<10;j++) {
13             for(int k=0;k<=j-2;k++) f[i][j]+=f[i-1][k];
14             for(int k=j+2;k<10;k++) f[i][j]+=f[i-1][k];
15         }
16 }
17 int Fc(int n) {
18     if(!n) return 0;
19     int ans=0,len=0,flag=1;
20     while(n)
21         b[++len]=n%10 , n/=10;
22     for(int i=1;i<len;i++)                                //统计所有长度小于 len 的
23         for(int j=1;j<10;j++) ans += f[i][j];
24     for(int j=1;j<b[len];j++) ans += f[len][j];                //长度为 len 最高位比 b[len] 小的
25     for(int i=len-1;i;i--) {                            //统计最高位为 b[len] 的 
26         for(int j=0;j<b[i];j++)
27             if(abs(b[i+1]-j)>=2) ans += f[i][j];
28         if(abs(b[i+1]-b[i])<2) {                        //n 不满足 不再统计后面的而且不计入 n 
29             flag=0; break;
30         }
31     }
32     if(flag) ans++;                                        //计入 n 
33     return ans;
34 }
35 
36 int main() {
37     int n,m;
38     init();
39     scanf("%d%d",&n,&m);
40     printf("%d",Fc(m)-Fc(n-1));
41     return 0;
42 }

 

posted on 2016-01-11 21:32  hahalidaxin  阅读(267)  评论(0编辑  收藏  举报