intmain(){ prework(); cin >> t; // 数据组数 while (t--) { scanf("%d", &n); // 题目中的X // 第n个魔鬼数有m位 for (m = 3; f[m][3] < n; m++); // 试填第i位,末尾已有k个6(k=3也表示已经是魔鬼数) for (int i = m, k = 0; i; i--) { // 从小到大枚举第i位填的数字j for (int j = 0; j <= 9; j++) { // 求出后边的i-1位有多少种填法能让整个数是魔鬼数 longlong cnt = f[i - 1][3]; if (j == 6 || k == 3) for (int l = max(3 - k - (j == 6), 0); l<3; l++) cnt += f[i - 1][l]; // 如果cnt比n小,说明第n个魔鬼数的第i位应该比j更大 if (cnt < n) { n -= cnt; } // 否则,第i位就应该是j else { if (k < 3) { if (j == 6) k++; else k = 0; } printf("%d", j); break; } } } cout << endl; } }
预处理 f(i,j) 后,我们可以求出第 X 小的魔鬼数的位数 cnt,然后就是从高位开始,确定每一位的值是多少了?
如何确定每一位的值?
第一步,我们可以先算下有多少个魔鬼数,首先是 i−1 位的魔鬼数,然后从 09 遍历 i 位数字时,可能这位数字是 6,当其为 6 或前 i 的前 3 个数都为 6 时,再加上可能的魔鬼数,这样遍历 i 位时总的魔鬼数就算出来了,当魔鬼数 cnt<X 时,说明当前遍历的这个数 i 太小了,这时 X 要:X−cnt。
intmain(){ prework(); int T; cin >> T; while (T--) { int n; cin >> n; int m = 3; while (f[m][3] < n) ++m; // 试填第 i 位,紧临第 i 位前已有 k 个 6 (k = 3 也表示已经是魔鬼数) for (int i = m, k = 0; i >= 1; --i) { // 从小到大枚举第 i 位填的数字 j for (int j = 0; j <= 9; ++j) { // 求出后边的 i - 1 位有多少种填法能让整个数是魔鬼数 longlong cnt = 0; //① 先加上前i - 1位已经是魔鬼数的情况 cnt += f[i - 1][3];
//② 再计算前i - 1位不是魔鬼数,但加上第i位后整个数是魔鬼数的情况 //k < 3 时表示在m ~ j + 1位,末尾有连续k个6 //k = 3 时表示在m ~ j + 1位,已经出现过连续3个6了 if (j == 6 || k == 3) { int need; // need 表示后边的 i - 1 位开头需要有 need 个 6
if (k == 3) need = 0; elseif (j == 6) need = 3 - (1 + k);
while (need <= 2) cnt += f[i - 1][need++]; } //如果cnt比n小,说明第n个魔鬼数的第i位比j大 if (cnt < n) { n -= cnt; } else { //否则,第n个魔鬼数第i位就是j if (k < 3) { if (j == 6) ++k; else k = 0; } cout << j; break; } } } cout << endl; } }
voidprework(){ for (int i = 1; i <= 10; ++i) { for (int j = 0; j <= 9; ++j) { if (i == 1) { f[i][j] = 1; continue; } for (int k = j; k <= 9; ++k) { f[i][j] += f[i - 1][k]; } } } }
intdp(int n){ if (n == 0) return1; vector<int> nums; while (n) nums.push_back(n % 10), n /= 10; int res = 0, last = 0; for (int i = nums.size() - 1; i >= 0; --i) { int x = nums[i]; for (int j = last; j < x; ++j) res += f[i + 1][j];//计算左分支 if (x < last) break; last = x;//存储右分支信息,右分支到最后才会计算 if (i == 0) res++; } return res; }
intmain(){ prework(); int l, r; while (cin >> l >> r) cout << dp(r) - dp(l - 1) << endl; }
voidprework(){ for (int i = 1; i <= 10; ++i) { for (int j = 0; j <= 9; ++j) { if (i == 1) { f[i][j] = 1; continue; } for (int k = 0; k <= 9; ++k) if (abs(j - k) >= 2) f[i][j] += f[i - 1][k]; } } }
intdp(int n){ if (n == 0) return0; vector<int> nums; while (n) nums.push_back(n % 10), n /= 10; int res = 0; int last = -2;
for (int i = nums.size(); i >= 1; --i) { int x = nums[i - 1]; for (int j = (i == nums.size()); j < x; ++j) if (abs(j - last) >= 2) res += f[i][j]; if (abs(x - last) >= 2) last = x; elsebreak; if (i == 1) ++res; } for (int i = 1; i < nums.size(); ++i) for (int j = 1; j <= 9; ++j) res += f[i][j]; return res; }
intmain(){ prework(); int l, r; cin >> l >> r; cout << dp(r) - dp(l - 1); }
voidprework(){ memset(f, 0, sizeof f); for (int j = 0; j <= 9; ++j) f[1][j][j % p]++; for (int i = 2; i < N; ++i) { for (int j = 0; j <= 9; ++j) { for (int k = 0; k < p; ++k) { for (int x = 0; x <= 9; ++x) { f[i][j][k] += f[i - 1][x][mod(k - j, p)]; } } } } }
intdp(int n){ if (n == 0) return1; vector<int> nums; while (n) nums.push_back(n % 10), n /= 10; int res = 0; int last = 0; for (int i = nums.size(); i >= 1; --i) { int x = nums[i - 1]; for (int j = 0; j < x; ++j) res += f[i][j][mod(-last, p)]; last += x; if (i == 1 && last % p == 0) res++; } return res; }
intmain(){ int l, r; while (cin >> l >> r >> p) { prework(); cout << dp(r) - dp(l - 1) << endl; } }
voidprework(){ for (int i = 0; i <= 9; ++i) if (i != 4) f[1][i] = 1; for (int i = 2; i < N; ++i) { for (int j = 0; j <= 9; ++j) { if (j == 4) continue; for (int k = 0; k <= 9; ++k) { if (k == 4 || j == 6 && k == 2) continue; f[i][j] += f[i - 1][k]; } } } }
intdp(int n){ if (n == 0) return1; vector<int> nums; while (n) nums.push_back(n % 10), n /= 10; int res = 0; int last = 0; for (int i = nums.size(); i >= 1; --i) { int x = nums[i - 1]; for (int j = 0; j < x; ++j) { if (j == 4 || last == 6 && j == 2) continue; res += f[i][j]; } if (x == 4 || last == 6 && x == 2) break; last = x; if (i == 1) res ++; } return res; }
intmain(){ prework(); int l, r; while (cin >> l >> r, l || r) { cout << dp(r) - dp(l - 1) << endl; } }