[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
",dis[0]+1);
}

int main(){
	solve();
}
原文地址:https://www.cnblogs.com/wzp-blog/p/13547804.html