ABC077D / ARC084B Small Multiple 题解

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;
}
posted @ 2024-08-20 15:41  bluewindde  阅读(7)  评论(0编辑  收藏  举报