[AtCoder Regular Contest 084] D - Small Multiple(同余最短路)

Problem

题目地址

Solution

性质1:\(x \equiv 0 \pmod{K}\)\(x \neq 0\) 则说明 \(x\)\(K\) 的倍数。

性质2: \((a*10+b)*10+c \equiv ((a*10+b)\%K) *10+c \pmod{K}\)

根据以上性质,我们可以把 \(0\)\(K-1\)\(K\) 个数看成 \(K\) 个点。其中 \(1\)\(K\) 每个点 \(x\)\((x*10+j)\),其中\(j \in \{0,1,2,...,9\}\),建 \(9\) 条边,每条边的权值是 \(j\)。从 \(1\)\(9\) 每个点一起出发跑最短路(多源最短路)。答案就是到 \(0\) 这个点的最短路。

Code

Talk is cheap.Show me the code.

#include<bits/stdc++.h>
#define mp make_pair
#define fi first
#define se second
#define INF 0x3f3f3f3f
using namespace std;
inline int read() {
    int x = 0, f = 1; char ch = getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
typedef pair<int,int> PII;
const int N = 1e6+7;
int K,cnt;
int head[N],dist[N];
bool vis[N];
struct Edge {
	int next,to,w;
}edge[N<<1];
inline void add(int u,int v,int w) {
	edge[++cnt] = (Edge)<%head[u],v,w%>;
	head[u] = cnt;
}
void Dijkstra() {
	priority_queue<PII> q;
	memset(dist, 0x3f, sizeof(dist));
	for(int i=1;i<=9;++i) {
		dist[i] = i; q.push(mp(-dist[i], i));
	}
	while(!q.empty()) {
		int u = q.top().se; q.pop();
		if(vis[u]) continue;
		vis[u] = 1;
		for(int i=head[u];i;i=edge[i].next) {
			int v = edge[i].to, w = edge[i].w;
			if(dist[u]+w < dist[v]) {
				dist[v] = dist[u]+w; q.push(mp(-dist[v], v));
			}
		}
	}
}
int main()
{
	K = read();
	for(int i=1;i<K;++i) {
		for(int j=0;j<=9;++j) {
			int u = i, v = (i*10 + j) % K, w = j;
			add(u,v,w);
		}
	}
	Dijkstra();
	printf("%d\n",dist[0]);
    return 0;
}
/*
79992

36
*/

Summary

  • 倍数放在模意义下为0,由此进行思考的套路。

  • 以 1-9 为起点,形如 \(x -> x*10 + j , j \in \{0,1,2,...,9\}\) 的建图,可以构造表示出所有的数。进一步的,赋予边权意义,跑最短路,可以得到一些有用的信息。

posted @ 2020-10-27 15:19  基地AI  阅读(226)  评论(0编辑  收藏  举报