【洛谷P2657】【BZOJ 1026】【SCOI2009】windy数
问题描述
windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。
windy想知道, 在A和B之间,包括A和B,总共有多少个windy数?
输入格式
包含两个整数,A B。
输出格式
一个整数
样例输入
#1
1 10
#2
25 50
样例输出
#1
9
#2
20
数据范围
100%的数据,满足 1 ≤ A ≤ B ≤ 2000000000 。
题解
数位dp。
先预处理f[i][j]表示位数为i,最高位为j的windy数的个数,f[i][j]=f[i-1][k](|j-k|≥2)
求小于n的wind数的个数,先统计位数小于n的位数的数中windy数的个数,∑f[i][j](i<len) (len为n的位数)
对于位数和n相同的数,从高位到低位枚举比n小的最高位
求区间[A,B]中windy数的个数,即为小于等于B的windy数的个数减去小于A的windy数的个数,而数位dp只能求小于n的满足条件的数的个数,那么就转化为小于B+1的windy数的个数减去小于A的windy数的个数
1 #include <cstdio> 2 const int p10[10]={1,10,100,1000,10000,1e5,1e6,1e7,1e8,1e9}; 3 int A,B,f[15][15],sa,sb,len,dig[15]; 4 int mabs(int x) 5 { 6 return x>0?x:-x; 7 } 8 int dp(int x) 9 { 10 int len,pre,ans=0,y,i,j; 11 for (len=9;x<p10[len];len--); len++; 12 for (i=1;i<len;i++) 13 for (j=1;j<10;j++) 14 ans+=f[i][j]; 15 y=x/p10[len-1]; 16 for (i=1;i<y;i++) ans+=f[len][i]; 17 pre=y; x%=p10[len-1]; 18 for (i=len-1;i>=1;i--) 19 { 20 y=x/p10[i-1]; 21 for (j=0;j<y;j++) 22 if (mabs(j-pre)>=2) 23 ans+=f[i][j]; 24 if (mabs(y-pre)<2) break; 25 pre=y; x%=p10[i-1]; 26 } 27 return ans; 28 } 29 int main() 30 { 31 int i,j,k,x; 32 scanf("%d%d",&A,&B); 33 for (i=0;i<10;i++) f[1][i]=1; 34 for (i=2;i<=10;i++) 35 for (j=0;j<=9;j++) 36 for (k=0;k<=9;k++) 37 if (mabs(j-k)>=2) 38 f[i][j]+=f[i-1][k]; 39 printf("%d",dp(B+1)-dp(A)); 40 return 0; 41 }