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;
}
posted @ 2025-04-04 14:18  quanjun  阅读(13)  评论(0)    收藏  举报