数位 dp

void solve() { int x, k; cin >> x >> k; int y = x + k; x--;
auto cal = [](int x) { vector<int> res; while (x) { res.emplace_back(x % 10); x /= 10; } reverse(res.begin(), res.end()); return res; };
auto a = cal(x); auto b = cal(y); int n = 0;
auto work = [&](vector<int> a) -> vector<int> { if (a.empty()) { // 直接不允许 0 作为有效值,所以 dp[0] 恒等于 0 // 这个规定非常重要,避免了前导 0 的存在!!! return vector<int>(11, 0); } // dp: 0 代表没有贴着上界,1 代表贴着上界 vector dp(1 << 10, vector<int>(2)); // 由于不允许存在前导 0,因此从 1 开始初始化 for (int i = 1; i < a[0]; i++) { dp[1 << i][0] = 1; } dp[1 << a[0]][1] = 1; for (int i = 1; i < n; i++) { auto ndp = dp; dp.assign(1 << 10, vector<int>(2, 0)); // 由于不允许存在前导 0,因此从 1 开始初始化 // 这里是说,构建的数从第 i 位开始, // 会带来一些额外的贡献,同时由于 i 已经不是最高位了, // 所以 0 ~ 9 都是合法的! for (int j = 1; j < 10; j++) { dp[1 << j][0]++; } for (int j = 0; j < (1 << 10); j++) { // 0 for (int k = 0; k < 10; k++) { dp[j | 1 << k][0] += ndp[j][0]; } // 1 for (int k = 0; k < a[i]; k++) { dp[j | 1 << k][0] += ndp[j][1]; } dp[j | 1 << a[i]][1] += ndp[j][1]; } } vector<int> cnt(11); for (int j = 0; j < (1 << 10); j++) { int k = 0; while (j >> k & 1) k++; assert(k <= 10); cnt[k] += dp[j][0] + dp[j][1]; } return cnt; };
n = a.size(); auto low = work(a); n = b.size(); auto cnt = work(b); for (int i = 0; i <= 10; i++) { cnt[i] -= low[i]; }
for (int i = 10; i >= 0; i--) { if (cnt[i]) { cout << i << ' ' << cnt[i] << "\n"; return; } }}