ABC077D / ARC084B Small Multiple 題解

bluewindde發表於2024-08-20

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;
}

相關文章