bzoj 1026 [SCOI2009]windy数(数位DP)
1026: [SCOI2009]windy数
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 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
1 10
【输入样例二】
25 50
Sample Output
【输出样例一】
9
【输出样例二】
20
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 阅读(273) 评论(0) 编辑 收藏 举报