【AtCoder】Small Multiple

Des

题目链接

求k的所有倍数中,各个数字和最小的那一个是多少。

Sol

emmm……很巧妙的一道题

建图方法特别有意思= ̄ω ̄=

首先,考虑暴力(一个一个枚举倍数,找最小值)肯定不现实,

那,还能从哪些方面入手呢?

  • 数位?
  • 余数?

观察数据范围,八九不离十了

让我们尝试一下下

那怎么用余数和数位跟倍数扯上关系呢?

可以想到,数 \(x\) 的倍数模上 \(x\) 的余数是 \(0\),我们就可以用这个性质来胡乱搞一发。。

呐,令 \(dis[i]\)\(k\)\(i\) 的数 的最小数字和。

那么,我们就只用考虑在他后面添数字 0~9

假设我们当前状态为 \(x\), 添加的数字为 \(i\), 则添加后的表示显然为 \(y = (x * 10 + i) % k\)

\[dis[y] = min(dis[x] + i) \]

其实就是跑一个最短路。。。

初始条件就是,把所有 \(dis\) 赋成最大值,然后 \(dis[i] = i(1 \le i \le 9)\) —— 只有一位数字时的情况。

然后就最短路模板直接来

很明显,答案就是 \(dis[0]\)

Code


#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue> 
using namespace std;
const int N = 1e5 + 5;
int dis[N], k;
bool vis[N];

void bfs() {
	queue<int> q;
	memset(dis, 0x3f, sizeof(dis));
	for(int i = 1; i <= 9; i ++) q.push(i), dis[i] = i, vis[i] = 1;
	int now, ver;
	while(!q.empty()) {
		now = q.front(), q.pop(), vis[now] = 0;
		for(int i = 0; i <= 9; i ++) {
			ver = (now * 10 + i) % k;
			if(dis[ver] > dis[now] + i) {
				dis[ver] = dis[now] + i;
				if(!vis[ver]) q.push(ver), vis[ver] = 1; 
			}
		}
	}
}

int main() {
	
	scanf("%d", &k);
	bfs();
	printf("%d\n", dis[0]);
	return 0;
}

posted @ 2021-09-16 17:37  Spring-Araki  阅读(47)  评论(0编辑  收藏  举报