【洛谷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  } 

 

posted @ 2018-10-31 10:19  清翠  阅读(...)  评论(... 编辑 收藏