给定一个整数 (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
",dis[0]+1);
}
int main(){
solve();
}