ABC077D / ARC084B Small Multiple 题解

AtCoder Luogu

考虑数位和的来源:从 1 开始进行若干次 ×10+1 操作可以得到任意正整数,此时 +1 操作的次数为其数字和。注意不能连续进行 10 次及以上 +1 操作。

不难列出转移,设 f(i) 表示 i 的数字和,则:

  • f(10i)=f(i)
  • f(i+1)=f(i)+1

考虑题目求 k 的正整数倍,使用 同余最短路,在模 k 意义下建图:

  • i010i
  • i1i+1

答案即为 10 的最短路。因为进行 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 @   bluewindde  阅读(10)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示