[ARC084B] Small Multiple 解题报告
给定一个整数 \(K\) ,求一个 \(K\) 的整数倍 \(SUM\) ,使得 \(SUM\) 的数位累加和最小。
选拔考的最后一题,我还以为是什么数学+贪心。。。
出来老师说是最短路,震撼了我一会。
感觉这个模型也挺妙的,可以只考虑所有数字对于 \(K\) 的模数,然后按照各位数字之和来转移。
对于数字 \(x\) ,转移有两种:
-
转移到 \(x+1\) ,各位数字之和 \(+1\) 。
-
转移到 \(10x\) ,各位数字之和不变。
然后可以以模数为点,储存模数为 \(x\) 的数字的各位数字之和的最小值,然后跑最短路。
可以发现第一种情况不一定是合法的,因为可能会进位,但是如果从 \(1\) 开始跑最短路,存在进位就要经过至少 \(9\) 次 \(+1\) 操作,可以证明这一定不是最短路。
然后这题就变成一道最短路问题了。
#include<bits/stdc++.h>
using namespace std;
const int M=1e5+5;
int read(){
int x=0,y=1;char ch=getchar();
while(ch<'0'||ch>'9') y=(ch=='-')?-1:1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*y;
}
int n,tot=0,first[M];
struct Edge{ int nxt,to,w; }e[M*10];
void add(int x,int y,int z){
e[++tot]=(Edge){first[x],y,z};
first[x]=tot;
}
struct Dian{
int id,val;
bool operator <(const Dian &x) const{ return x.val<val; }
};
priority_queue<Dian> q;int dis[M];bool inq[M];
void DIJ(){
for(int i=0;i<n;i++) dis[i]=1e9,inq[i]=0;
q.push((Dian){1,0});dis[1]=0;
while(!q.empty()){
int u=q.top().id;q.pop();
if(inq[u]) continue ;inq[u]=1;
for(int i=first[u];i;i=e[i].nxt){
int v=e[i].to,w=e[i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
if(!inq[v]) q.push((Dian){v,dis[v]});
}
}
}
}
void solve(){
n=read();
for(int i=1;i<n;i++) for(int j=0;j<9;j++) add(i,(i*10+j)%n,j);
DIJ();
printf("%d\n",dis[0]+1);
}
int main(){
solve();
}