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 }