快2个月没接触算法了,今天开始每天坚持算法学习,坚持刷题
涉及算法:广度搜索+同余模定理
题目大意:给定一个正整数n(1<=n<=200)求出任意一个n的倍数m,要求m只能由0、1表示。
题目分析:
bfs的过程如下:
1 mod n
10 mod n 11 mod n
100 mod n 101 mod n 110 mod n 111 mod n
.........
这样下去会出现大数,为了避免大数的出现,我们运用了下面的方法,
同余公式:
(a+b)% n = (a%n+b)%n=(a+b%n)%n=(a%n+b%n)% n
(a*b)% n = (a%n*b)%n=(a*b%n)%n=(a%n*b%n)% n
如果我们现在有一个数k,要看是否是n的倍数,由于k只能由0或1组成,则k=(k/10)*10+1(若k为基数)或k=(k/10)*10(若k为偶数),所以可以得到:k=(k/10)*10+k%2,k%n=((k/10)*10+k%2)%n=(((k/10)%n*10)%n+k%2)%n=((k/10)%n*10+k%2)%n,这样(k/10)%n的值永远不会大于n,,解决了大数问题。我们用mod[i]表示i对n求余的结果,求mod[i]时,显然要用到mod[i/10],这下问题又来了,数组的下标i/10会很大,我们需要开一个很大的数组,这显然是不现实的,为了解决这个问题,我们可以用10进制数来表示2进制,例如,用2来表示10、16来表示10000、33来表示100001,,这样数组就不用开到很大,若我们要求mod[33]只需要知道mod[16]即可,可以推出公式mod[i]=(mod[i/2]*10+i%2)%n,当mod[i]=0时,说明找到了合适的i,输出i的二进制形式就可以了
代码如下:
import java.util.Scanner;
public class Main_1426 {
static int a;
static int[] mod=new int[524287];
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
a=in.nextInt();
while(a!=0){
bfs();
a=in.nextInt();
}
}
static void bfs(){
mod[1]=1;
int i=0;
for(i=2;mod[i-1]!=0;i++){
mod[i]=(mod[i/2]*10+i%2)%a;
}
i--;
int tmp=0;
while(i>0){
mod[tmp++]=i%2;
i/=2;
}
for(i=0;i<tmp;i++){
System.out.print(mod[tmp-i-1]);
}
System.out.println();
}
}