arc084_b 『D - Small Multiple』题解 同余最短路
题目链接:https://atcoder.jp/contests/arc084/tasks/arc084_b
题目大意:
找到一个数位和最小的整数,这个整数是 \(K(\le 10^5)\) 的倍数,输出数位和。
解题思路:
观察到任意一个正整数都可以从 \(1\) 开始,按照某种顺序执行乘 \(10\)、加 \(1\) 的操作,最终得到,而其中加 \(1\) 操作的次数就是这个数的数位和。这提示我们使用最短路。
对于所有 \(0 \le k \le n-1\),从 \(k\) 向 \(10k\) 连边权为 \(0\) 的边;从 \(k\) 向 \(k+1\) 连边权为 \(1\) 的边。(点的编号均在模 \(n\) 意义下)
每个 \(n\) 的倍数在这个图中都对应了 \(1\) 号点到 \(0\) 号点的一条路径,求出 \(1\) 到 \(0\) 的最短路即可。某些路径不合法(如连续走了 \(10\) 条边权为 \(1\) 的边),但这些路径产生的答案一定不优,不影响答案。
参考链接:https://oi-wiki.org/graph/mod-shortest-path/#例题2
示例程序:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int x;
long long dis[maxn];
bool vis[maxn];
struct Edge { int v, w; };
vector<Edge> g[maxn];
struct Node {
int u;
long long dis;
bool operator < (const Node &b) const {
return dis > b.dis;
}
};
void dijkstra() {
priority_queue<Node> que;
fill(dis, dis+x, -1);
dis[1] = 1;
que.push({1, 1});
while (!que.empty()) {
Node nd = que.top();
que.pop();
int u = nd.u;
long long _dis = nd.dis;
if (vis[u]) continue;
vis[u] = true;
for (int i = 0; i < 2; i++) {
int v, w;
if (i == 0) {
v = (u + 1) % x;
w = 1;
}
else {
v = u * 10 % x;
w = 0;
}
if (u == v) continue;
if (dis[v] == -1 || dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
que.push({ v, dis[v] });
}
}
}
}
int main() {
cin >> x;
dijkstra();
cout << dis[0] << endl;
return 0;
}