[AtCoder Regular Contest 084] D - Small Multiple
阿新 • • 發佈:2020-10-27
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\)
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\}\) 的建圖,可以構造表示出所有的數。進一步的,賦予邊權意義,跑最短路,可以得到一些有用的資訊。