abc077d <思维 + 最短路 (将构造数字过程视为最短路)>
// https://atcoder.jp/contests/abc077/tasks/arc084_b
// <思维 + 最短路>
// 参考:
// 1. https://www.cnblogs.com/BaseAI/p/13885049.html <同余最短路>
// 2. https://blog.csdn.net/weixin_44178736/article/details/108390895
// 思路:
// 1. 假设有k的倍数x, 其最高位为i, 现在从高位到低位构造x;
// 2. x是k的倍数, 可表示为 x % k = 0
// 3. 当构造过程中, 已经构造了部分高位, 现在有数 y,
// 则若在低位添加数位 j, 则 y 变为 y*10 + j;
// 4. 在构造x的过程中, 正在构造的数y实际上仅需在模k意义下进行,
// 即, 当不断向y的低位添加数位时, y总是%k, 保持 0<=y<k;
// 5. 则构造过程中y一共仅有 0~k-1这k个有限的状态, 每个状态视为一个结点;
// 构造过程视为节点间的跳转, 若视为最短路问题, 则终点必然为 0 (即 %k=0 );
// 起点可为 1~9 (即x的最高位的数字, 注意不能为0, 为前导零);
// 6. 图中所有可能的边, 可通过 u (1~k-1) 向 v = 10*u+i (i= 0~9) 连接边得到
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
using LL = long long;
const int N = 1e5 + 10;
struct Node
{
int dis, u;
bool operator<(Node const &t) const
{
return dis > t.dis; // 小根堆
}
};
struct Edge
{
int v, w;
};
vector<Edge> adj[N];
int dis[N];
bool st[N];
void dijkstra()
{
priority_queue<Node> q;
memset(dis, 0x3f, sizeof dis);
for (int i = 1; i <= 9; i ++) q.push({i, i}), dis[i] = i; // 可视为一个虚起点向这9个节点连边, 权重为i
while(q.size())
{
int u = q.top().u; q.pop();
if(st[u]) continue;
st[u] = true;
for (auto [v, w]: adj[u])
{
if (dis[u] + w < dis[v])
{
dis[v] = dis[u] + w;
q.push({dis[v], v});
}
}
}
}
void solv()
{
int k;
cin >> k;
for (int u = 1; u < k; u ++)
for (int i = 0; i <= 9; i ++)
{
int v = (u * 10 + i) % k;
adj[u].push_back({v, i});
}
dijkstra();
cout << dis[0] << endl;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int T = 1;
// cin >> T;
while (T --)
{
solv();
}
return 0;
}
本文来自博客园,作者:O2iginal,转载请注明原文链接:https://www.cnblogs.com/o2iginal/p/17544223.html