【数位DP】Windy数
作者:互联网
【题目链接】
【题目描述】
不含前导零且相邻两个数字之差至少为 2 的正整数被称为 windy 数。在 a 和 b 之间,包括 a 和 b ,总共有多少个 windy 数?
【输入】输入只有一行两个整数,分别表示 a 和 b。1≤a,b≤2 x 109。
【输出】
输出一行一个整数表示答案。
【输入样例】
1 10 【输出样例】 9 与不降数一样,按位分情况讨论的,将数num划分为anan-1...a2a1,从最高位开始到低位,划分为0~ai-1与ai,如果第i位上填的是0~ai-1,那么后面的所有位数都可以填0~9,如果第i位是ai,那么就继续往下讨论下一位,通过这种划分方式,可以保证我们枚举的数不超过num。 此外需要结合前缀和的思想,即求区间[a,b]的windy数个数可转化为求count(b) - count(a - 1)的值。 windy数与不降数除了性质不同外,最大区别就在于windy数不含前导零,而不降数存在前导零并不影响其性质的判定。 举例:352 由于不含前导零,故首位不可从0开始枚举,而是枚举1XX、2XX,30X、31X、32X、33X、34X,350、351、352;而且因为前导零的关系,枚举的时候就无法枚举仅有2位、1位的情况,因此小于n位的情况需要单独统计并累加。 预处理与不降数类似:1 for(int i = 0;i <= 9;++i) 2 f[1][i] = 1; 3 for(int i = 2;i < N;++i) 4 for(int j = 0;j <= 9;++j) 5 for(int k = 0;k <= 9;++k) 6 if(abs(j - k) >= 2) 7 f[i][j] += f[i - 1][k];
之后只需要把数字拆分出来,分情况枚举,并且不要忘记统计小于n位的情况即可。
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 const int N = 12; 5 int f[N][N]; 6 int num[N]; 7 8 int count(int n) 9 { 10 if(n == 0) 11 return 0; 12 int cnt = 0; 13 while(n) 14 { 15 num[++cnt] = n%10; 16 n /= 10; 17 } 18 int res = 0; 19 int now = 0,last = -2; 20 for(int i = cnt;i > 0;--i) 21 { 22 now = num[i]; 23 for(int j = (i == cnt);j < now;++j) 24 { 25 if(abs(j - last) >= 2) 26 res += f[i][j]; 27 } 28 if(abs(last - now) < 2) 29 break; 30 last = now; 31 if(i == 1) 32 res++; 33 } 34 for(int i = 1;i < cnt;++i) //统计小于n位的情况,且不要忘记小于n位的情况中,首位也是从1开始枚举,而不是0 35 for(int j = 1;j <= 9;++j) 36 res+= f[i][j]; 37 return res; 38 } 39 40 int main() 41 { 42 for(int i = 0;i <= 9;++i) 43 f[1][i] = 1; 44 for(int i = 2;i < N;++i) 45 for(int j = 0;j <= 9;++j) 46 for(int k = 0;k <= 9;++k) 47 if(abs(j - k) >= 2) 48 f[i][j] += f[i - 1][k]; 49 int n,m; 50 cin >> n >> m; 51 cout << count(m) - count(n - 1) << endl; 52 return 0; 53 }
标签:cnt,int,Windy,windy,num,枚举,now,DP,数位 来源: https://www.cnblogs.com/fengshi99/p/15408542.html