基准时间限制:1 秒 空间限制:131072 KB 分值: 40
难度:4级算法题
给定一个自然数N,找出一个M,使得M > 0且M是N的倍数,并且M的10进制表示只包含0或1。求最小的M。
例如:N = 4,M = 100。
Input
输入1个数N。(1 <= N <= 10^6)
Output
输出符合条件的最小的M。
Input示例
4
Output示例
100
解题思路:运用队列存储余数,逐一判断,知道满足条件,每次在M后面添加一位数a(题目要求其中a为0或者为1),使M扩大为10*M+a
即:原数为M,扩大后的数为M1=10*M+a
将其对mod取模,则:mod_M=M%mod mod_M1=(10*M+a)%mod = (10*M%mod + a%mod)%mod = (10*M%mod+a)%mod = (10*mod_M+a)%mod
由此我们可以知道,当M满足条件时,则:mod_M1=0
可以将其假设成为一个带权值的图,其权值为数字0或者1,其顶点值为余数,最后可以看成从起点到第一个顶点为0的路径就是最后结果;
在余数入队的时候要判断是否在之前就出现过,如果出现过,则不入队,因为如果出现重复的,那么就会出现无限循环,这样永远也得不到余数为0 的这个条件,所以直接舍去,如果没有出现过,则将其入队,并且用b数组将其标记,a数组用来保存权值,其中两者都以余数作为下标;则b数组保存路径,a数组保存权值,最后根据路径输出所以权值。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
int a[maxn],b[maxn];
void print(int s)///输出函数
{
if(s==-1) return ;
print(b[s]);
printf("%d",a[s]);
}
int main()
{
int n,f=0,s;
scanf("%d",&n);
if(n==1) {printf("1\n"); return 0;}///1作为特判
queue<int>Q;
Q.push(1);
b[1] = -1;
a[1] = 1;
while(!Q.empty())
{
s=Q.front();
Q.pop();
int c1=10*s%n,c2=(10*s+1)%n;
if(c1 == 0) {f=0; break;}
if(c2 == 0) {f=1; break;}
if(!b[c1]){Q.push(c1); a[c1] = 0; b[c1]=s;}///判断是否出现循环
if(!b[c2]){Q.push(c2); a[c2] = 1; b[c2]=s;}
}
print(s);
printf("%d\n",f);
return 0;
}