AtCoder Luogu
考慮數位和的來源:從 \(1\) 開始進行若干次 \(\times 10\) 和 \(+1\) 操作可以得到任意正整數,此時 \(+1\) 操作的次數為其數字和。注意不能連續進行 \(10\) 次及以上 \(+1\) 操作。
不難列出轉移,設 \(f(i)\) 表示 \(i\) 的數字和,則:
- \(f(10 i) = f(i)\)
- \(f(i + 1) = f(i) + 1\)
考慮題目求 \(k\) 的正整數倍,使用 同餘最短路,在模 \(k\) 意義下建圖:
- \(i \xrightarrow{0} 10 i\)
- \(i \xrightarrow{1} i+1\)
答案即為 \(1\) 到 \(0\) 的最短路。因為進行 \(10\) 次及以上 \(+1\) 操作一定更劣,無需特別處理。
#include <iostream>
#include <queue>
#include <string.h>
#include <vector>
using namespace std;
int n;
int dis[100005];
vector<pair<int, int>> vec[100005];
signed main() {
#ifndef ONLINE_JUDGE
freopen("ABC077D.in", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 0; i < n; ++i) {
vec[i].push_back({10 * i % n, 0});
vec[i].push_back({(i + 1) % n, 1});
}
memset(dis, 0x3f, sizeof dis);
dis[1] = 1;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
q.push({1, 1});
while (!q.empty()) {
auto [d, u] = q.top();
q.pop();
if (d != dis[u])
continue;
for (auto [v, w] : vec[u]) {
int dd = d + w;
if (dd < dis[v]) {
dis[v] = dd;
q.push({dd, v});
}
}
}
cout << dis[0] << endl;
return 0;
}