Solutions of Math - MarisaOJ: Marisa Online Judge

Solutions of Math

Select solution language

Write solution here.


chithanhnguyen    Created at    2 likes

## Thuật toán Xét một số $x$, giả sử ta thêm chữ số $c$ vào sau, thì $x$ trở thành $10 \times x + c$, suy ra $$ f(10 \times x + c) \equiv f(x) + c \ \textrm{(mod } k\textrm{)} $$ Khởi tạo các đỉnh của đồ thị là $0, 1, \ldots, k - 1$, tương ứng với các số dư khi chia cho $k$. Với mỗi đỉnh $u$, ta chữ số $d \ (0 \leq d \leq 9)$ đằng sau số có $f(x) \equiv u \ \textrm{(mod } k\textrm{)}$, khi đó ta thêm vào đồ thị cung $(u, v)$ có trọng số $d$, với $v = (u\times 10 + d) \ \textrm{mod} \ k$. Ta cần tìm $f(x)$ nhỏ nhất của số $x$ chia hết cho $k$, dễ thấy bài toán tương đương với tìm đường đi ngắn nhất đến đỉnh $0$. $\rightarrow$ Đây là bài toán cơ bản của Dijkstra, ta có thể xử lí bằng cách đảo chiều các cung của đồ thị. **Độ phức tạp.** $O((n + m) \log n)$ ## Cài đặt tham khảo ```cpp #include <bits/stdc++.h> using namespace std; #define int long long #define pii pair<int, int> const int MAXN = 1e5 + 5; const int INF = 1e18 + 5; int k; vector<pii> adj[MAXN]; int dist[MAXN]; void init() { cin >> k; for (int u = 0; u < k; ++u) { for (int w = 0; w <= 9; ++w) { if (u == 0 && w == 0) continue; int v = (u * 10 + w) % k; adj[v].push_back({u, w}); } } } void solve() { fill(dist, dist + MAXN, INF); dist[0] = 0; priority_queue<pii, vector<pii>, greater<pii>> pq; pq.push({0, 0}); while (!pq.empty()) { long long cost = pq.top().first; long long u = pq.top().second; pq.pop(); for (int i = 0; i < (int)adj[u].size(); ++i) { long long v = adj[u][i].first; long long w = adj[u][i].second; if (dist[v] > cost + w) { dist[v] = cost + w; pq.push({dist[v], v}); } } } int res = INF; for (int i = 1; i <= 9; ++i) if (dist[i] != INF) res = min(res, dist[i] + i); cout << res; } signed main() { ios_base::sync_with_stdio(0); cin.tie(nullptr); cout.tie(nullptr); init(); solve(); return 0; } ```