克苏鲁的规则:前言
这题蛮有意思的。
听同学说用bfs做的,然后写了bfs挂了。
然后看他们代码,嚯嚯,取模了,然后他们解释下懂了。
题解
part 1
我们称各位数之和叫 ,数叫做
。
首先呢,这个思想是从 开始广搜,对于每个
它有多个
,
比如对于 ,它可以是
,
,
,
那到什么时候为止呢?
或许你会想,这个数它不能超过
吧。。也许可作为限制条件。
那么接着,你就想怎么广搜,对于每个 ,你有两种选择,要么乘以
,要么给它加上
,其中注意到乘法是不影响
的。
这意味着, 在加上
后,可转移的新状态为
+
+
,把它们加入队列呗。
最后只要判断每次的num是否能整除 就行了。
遗憾的是这样会 。
part 2
不难注意到,每次的 若能整除
是就好了。进而
的模数
要是能整除
就好了。再进而要是我知道怎么操作会使
能整除
,并且要是这样对
搞,也
相同就好了。(嘿嘿,就是贪它一手。)
结果一想发现什么呢?我要是对 加
,相当于加在模数
上,我要是对
乘
,
中一部分能整除的数自然乘后还是乘除的,而不能整除的模数
会受到影响。
哎,这不就意味着,直接对 进行
与对
是等价的。
哦,那么这个时候乘多少个 的问题就看什么时候算的
见过了,就不乘了。加个记忆化,要是这个
我见过,就不扩展了,
出去。因为之前就扩展过了。
Code
#include<bits/stdc++.h>
#define int long long
#define sec second
#define fst first
#define pii pair<int,int>
using namespace std;
queue<pii> q;
signed main(){
// freopen("in.txt","r",stdin);
ios::sync_with_stdio(false);
int n;cin >> n;
map<int,int> v;
int t=1;
while(!v[t]) v[t]++,q.push({ t,1 }),t=(t * 10) % n;
while(q.size()){
int num=q.front().fst,cnt=q.front().sec;
if(num % n == 0){
cout << cnt << endl;
break;
}
num=(num + 1) * 10 % n;
while(!v[num]) v[num]++,q.push({ num,cnt + 1 }),num=(num * 10) % n;
q.pop();
}
return 0;
}