# Help Conan 10! - Solution
## 1. Quan sát
Theo đề bài, chúng ta cần tìm số các số $x$ thỏa mãn:
$$A <= x * f(x) <= B$$
với $f(x)$ là tích các chữ số của $x$.
$$ {A \over f(x)} <= x <= {B \over f(x)} $$
Dễ thấy rằng do $A >= 1$ nên $x \ne 0$ và $f(x) \ne 0$, suy ra mọi số $x$ thỏa mãn sẽ không chứa chữ số $0$ $(1)$
Do tích các chữ số của một số luôn nhỏ hơn hoặc bằng chính số đó nên $f(x) <= x$, suy ra
$$f(x)^2 <= x * f(x) <= 1e18$$ hay $f(x) <= 1e9$ $(2)$
Vì $f(x)$ ở đây là tích các chữ số từ $[1, 9]$ nên:
$$f(x) = 1^a . 2^b . 3^c . 4^d . 5^e . 6^f . 7^g . 8^h . 9^i = 2^{a_1} . 3^{a_2} . 5^{a_3} . 7^{a_4} (3)$$
Kết hợp cùng nhận xét $(2)$, nếu for qua 4 vòng ta nhận thấy rằng chỉ có đúng $5194$ bộ số $a_1, a_2, a_3, a_4$ phân biệt thỏa mãn điều kiện trên, ta hoàn toàn có thể lưu trước $5194$ tích đó thành một mảng.
Giờ đây bài toán rút gọn về:
- Với mỗi tích $f(x)$, cho $A' = {A \over f(x)}$, $B' = {B \over f(x)}$, có bao nhiêu số $x$ thỏa mãn:
$$A' <= x <= B'$$
## 2. Thuật trâu
Dễ thấy rằng ta có thể chạy 1 vòng từ $A'$ đến $B'$ rồi đếm xem có bao nhiêu số thỏa mãn. Tuy nhiên $x <= 1e18$ là quá lớn nên cách này sẽ TLE.
## 3. Lời giải
Đây là một biến thể của bài toán: Đếm số các số có tích các chữ số bằng $k$, vì giới hạn của bài là $1e18$, nên sẽ chỉ có tối đa $18$ chữ số, mỗi chữ số có $9$ cách chọn (từ nhận xét $(1)$).
Ta có thể sử dụng kỹ thuật **Digit DP** để xử lý bài toán này, gọi **dp[n][product]** là số các số có **n** chữ số và tích các chữ số bằng **product**, do tích các chữ số của một số có thể rất lớn nên từ nhận xét $(3)$, ta có thể tách bớt ra thành **dp[n][a1][a2][a3][a4]**.
Ta có thể giải quyết mỗi bài toán dp trên bằng đệ quy: **solve(n, num, num_digit)** là số các số thỏa mãn có **n** chữ số, **num** lưu số ta đã chọn ở lần đệ quy trước và **num_digit** lưu số vị trí còn nhét được thêm.
Độ phức tạp: $O(5194 * g(B))$ với $g(B) =$ số chữ số của $B$.
## Code:
```
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll maxn = 2e5 + 5;
const ll maxn_sqrt = 1e9;
const ll maxn_ll = 1e18;
const ll mod = 1e9 + 7;
ll binpow(ll a, ll b)
{
ll r = 1;
for (;b; a = a * a, b >>= 1) if (b & 1) r = r * a; return r;
}
ll dp[19][30][30][30][30];
ll ans = 0;
ll current[4] = {0, 0, 0, 0};
// 2^a1 * 3^a2 * 5^a3 * 7^a4
ll base[10][4] =
{
{0, 0, 0, 0}, // 1
{0, 0, 0, 0}, // 1
{1, 0, 0, 0}, // 2
{0, 1, 0, 0}, // 3
{2, 0, 0, 0}, // 4
{0, 0, 1, 0}, // 5
{1, 1, 0, 0}, // 6
{0, 0, 0, 1}, // 7
{3, 0, 0, 0}, // 8
{0, 2, 0, 0} // 9
};
bool validate(ll min_num, ll max_num, ll l, ll r)
{
if (min_num >= l && max_num <= r) return true;
return false;
}
ll solve(ll n, ll num, ll num_digit, ll l, ll r)
{
if (num > r || (num + num_digit - 1) < l) return 0;
if (n >= 18)
{
//cout << current[0] << ' ' << current[1] << ' ' << current[2] << ' ' << current[3] << '\n';
return !current[0] && !current[1] && !current[2] && !current[3];
}
if (validate(num, (num + num_digit - 1), l, r) && dp[n][current[0]][current[1]][current[2]][current[3]] != -1) return dp[n][current[0]][current[1]][current[2]][current[3]];
// kiểm tra trường hợp số đang xét có quá khoảng l r cần biết không (max là nhét thêm toàn chữ số 9 vào)
ll cnt = 0;
ll start;
if (num == 0) start = 0;
else start = 1;
for (ll i = start; i <= 9; ++i)
{
bool flag = true;
for (ll j = 0; j < 4; ++j)
{
if (base[i][j] > current[j])
{
flag = false;
break;
}
}
if (!flag) continue;
for (ll j = 0; j < 4; ++j) current[j] -= base[i][j]; // Giảm số mũ của chữ số đã chọn xuống
ll addnew_num = (i * (num_digit / 10));
cnt += solve(n + 1, num + addnew_num, (num_digit / 10), l, r); // Nhét chữ số đã chọn và đệ quy đến trường hợp nhỏ hơn tiếp theo
for (ll j = 0; j < 4; ++j) current[j] += base[i][j]; //Reset lại số mũ lũy thừa về base case ban đầu, xét các chữ số tiếp theo
}
if (validate(num, (num + num_digit - 1), l, r))
{
dp[n][current[0]][current[1]][current[2]][current[3]] = cnt; // lưu trường hợp đệ quy vào dp
return dp[n][current[0]][current[1]][current[2]][current[3]];
}
else return cnt;
}
int main()
{
memset(dp, -1, sizeof(dp));
ll l, r;
cin >> l >> r;
//tính hết mọi bộ số có tích thỏa mãn
//do chỉ có 5194 tích thỏa mãn nên lưu trước vào một mảng riêng hoặc gen bằng đệ quy cũng được
for (ll i = 0; i <= 30; ++i)
{
for (ll j = 0; j <= 30; ++j)
{
for (ll k = 0; k <= 30; ++k)
{
for (ll q = 0; q <= 30; ++q)
{
ll n = binpow(2, i) * binpow(3, j) * binpow(5, k) * binpow(7, q);
if (n <= maxn_sqrt && n > 0)
{
current[0] = i;
current[1] = j;
current[2] = k;
current[3] = q;
// do x có thể bé hơn n (x / n = 0)
ans += solve(0, 0, maxn_ll, (l + n - 1) / n, r / n); // a/x <= x <= b/x
//cout << n << '\n';
}
}
}
}
}
cout << ans << '\n';
}
```