ABC077D / ARC084B Small Multiple 题解
考虑数位和的来源:从 \(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;
}