[BZOJ 1026] [SCOI 2009] Windy数 【数位DP】
题目链接:BZOJ - 1026
题目分析
这道题是一道数位DP的基础题,对于完全不会数位DP的我来说也是难题..
对于询问 [a,b] 的区间的答案,我们对询问进行差分,求 [0,b] - [0,a-1] 的答案。这样就化繁为简了。
具体过程见代码中的注释。
代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int MaxBit = 13; int A, B; int f[MaxBit][11], Bit[MaxBit]; inline int Abs(int a) { return a >= 0 ? a : -a; } //计算小于x的数的答案 int Get(int x) { if (x == 0) return 0; int ret = 0, l = 0; while (x) { Bit[++l] = x % 10; x /= 10; } //统计位数不足l位的答案 for (int i = 1; i <= l - 1; ++i) { for (int j = 1; j <= 9; ++j) { ret += f[i][j]; } } //最高位可以在[1, Bit[l]-1]之间变化 for (int i = 1; i <= Bit[l] - 1; ++i) ret += f[l][i]; //固定后面的(l-i)位,然后第i位可以在[0, Bit[i]-1]之间变化 for (int i = l - 1; i >= 1; --i) { for (int j = 0; j <= Bit[i] - 1; ++j) { if (Abs(j - Bit[i + 1]) >= 2) ret += f[i][j]; } //无法固定第i位 if (Abs(Bit[i + 1] - Bit[i]) < 2) break; } return ret; } int main() { //f[i][j]表示第i位是j的答案数 for (int i = 0; i <= 9; ++i) f[1][i] = 1; for (int i = 1; i <= 10; ++i) { for (int j = 0; j <= 9; ++j) { for (int k = 0; k <= 9; ++k) { if (Abs(k - j) >= 2) f[i][j] += f[i - 1][k]; } } } scanf("%d%d", &A, &B); //对询问进行差分,化繁为简 printf("%d\n", Get(B + 1) - Get(A)); return 0; }