bzoj 1026 windy数

题目大意:

定义一种windy数:不含前导零且相邻两个数字之差至少为2的正整数被称为windy数

求在A和B之间,包括A和B,总共有多少个windy数

思路:

一眼数位dp

具体见注释

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstdlib>
 6 #include<cstring>
 7 #include<queue>
 8 #include<map>
 9 #include<vector>
10 #define ll long long
11 #define inf 2147483611
12 #define MAXN 20
13 using namespace std;
14 inline int read()
15 {
16     int x=0,f=1;char ch=getchar();
17     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
18     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
19     return x*f;
20 }
21 int a,b,l[11],cnt;
22 ll dp[11][11],res;
23 ll solve(int x)//可以得到结果是小于等于b的所有数减去小于a的所有数 
24 {
25     res=cnt=0;
26     while(x) l[++cnt]=x%10,x/=10;//把数字分解为字符串 cnt为x个数 
27     for(int i=1;i<l[cnt];i++) res+=dp[cnt][i];//求出小于x但是位数等于cnt的所有答案 
28     for(int i=1;i<=cnt-1;i++)//求出位数不到cnt的所有答案 
29         for(int j=1;j<10;j++) res+=dp[i][j];
30     for(int i=cnt-1;i>0;i--)//求出前i-1位和x一样的数且第i-1位小于原数的第i-1位的个数 
31     {
32         for(int j=0;j<l[i];j++)
33             if(abs(j-l[i+1])>=2) res+=dp[i][j];//枚举这一位的个数 
34         if(abs(l[i+1]-l[i])<2) break;//本身x这两位不满足条件,无法满足条件 退出循环 
35     }
36     return res;
37 }
38 int main()
39 {
40     a=read(),b=read();
41     //下面是预处理出整个dp数组:表示长度为j的数首位为i的所有数的个数
42     for(int i=0;i<10;i++) dp[1][i]=1;
43     for(int i=2;i<=10;i++)
44         for(int j=0;j<10;j++)
45             for(int k=0;k<10;k++) if(abs(j-k)>=2) dp[i][j]+=dp[i-1][k];
46     printf("%lld",solve(b+1)-solve(a));
47 }
View Code

 

posted @ 2017-11-17 20:34  jack_yyc  阅读(150)  评论(0编辑  收藏  举报