题意大致是给定一个n(1~200),求出n的一个倍数k,但k的每一位都必须是0或1。Special Judge 的意思是答案不唯一,比如说n=2时,k=10对,k=100也对,只要输出一个符合要求的即可,没有说要最小。这个题有点像数学题,但还用到了bfs,还算比较综合吧。难点在于k比较大的时候如何表示,很显然一个int,long都是不行的。还有就是数很大时穷举去计算是否能整除也很浪费时间。
解决的办法是利用同余数定理。
首先我们利用 同余数定理 对得到余数的方式进行一个优化
(a*b)%n = (a%n *b%n)%n
(a+b)%n = (a%n +b%n)%n
以n=6为例,
比如说k=110时,余数是2,现在要求1100和1101的余数是否为0,下面求1101的余数:
由同余数定理 (110*10+1)%6 = ((110*10)%6+1%6 )%6 = ((110%6 * 10%6)%6 +1 )%6
110%6正好是少一位的数(k=110)的余数,是我们已经求过且保存在mod【】中的,所以说求1100和1101时只需知道110的余数,用(余数*10+0/1)%6就可以表示1100/1101%6了。
所以当前步(110*10+1)%6可以转变为 (2*10+1)%6=2。
接下来的问题就是当计算出某个k值得余数为0了,但是怎么知道k是多少?因为我们只保存了k的每个余数,并没有保存k的每一位,事实上也没有办法保存k的每一位,因为到后面可能性越来越多。这个时候我发现可以利用mod【i】数组中的下表i来计算,因为下标i正好是k的十进制的表示!因为k只有0,1组成,按照小到大的顺序不重复不遗漏地取值正好相当于是二进制计数(好好体会一下~)
我的代码:
#include<iostream>
using namespace std;
int mod[600000]; //开大一点防止RE
int main(){
int n;
while(cin>>n&& n){
memset(mod,-1,sizeof(mod));
int output[110];
int front,rear;
front=rear=1;
mod[rear++]=1%n;
while(front<rear){
int tmp=mod[front++];
if ((tmp*10)%n==0) break; //利用前一步的余数代替进行计算
else mod[rear++]=(tmp*10)%n;
if ((tmp*10+1)%n==0) break;
else mod[rear++]=(tmp*10+1)%n;
}
int i=0;
while(rear>1){ //根据rear值计算各位,其实就是将rear值用二进制表示
output[i++]=rear%2;
rear=rear/2;
}
output[i]=rear;
for (int j=i;j>=0;j--){ //逆向输出即可
cout<<output[j];
}
cout<<endl;
}
return 0;
}
欢迎交流讨论~