【BFS+同余模定理】Find The Multiple(POJ1426)
Description
Input
Output
Sample Input
2 6 19 0
Sample Output
10 100100100100100100 111111111111111111
Source
因此k=1不是所求,存储余数 1
2、搜索下一位,下一位可能为0,即 k*10+0,此时k=10,那么k%6=4
可能为1,即 k*10+1,此时k=11,那么k%6=5
由于余数均不为0,即k=10与k=11均不是所求
3、继续搜索第三位,此时有四种可能了:
对于k=10,下一位可能为0,即 k*10+0,此时k=100,那么k%6=4
下一位可能为1,即 k*10+1,此时k=101,那么k%6=5
对于k=11,下一位可能为0,即 k*10+0,此时k=110,那么k%6=2
下一位可能为1,即 k*10+1,此时k=111,那么k%6=3
由于余数均不为0,即k=100,k=101,k=110,k=111均不是所求
4、继续搜索第四位,此时有八种可能了:
对于k=100,下一位可能为0,即 k*10+0,此时k=1000,那么k%6=4
下一位可能为1,即 k*10+1,此时k=1001,那么k%6=5
对于k=101,下一位可能为0,即 k*10+0,此时k=1010,那么k%6=2
下一位可能为1,即 k*10+1,此时k=1011,那么k%6=3
对于k=110,下一位可能为0,即 k*10+0,此时k=1100,那么k%6=2
下一位可能为1,即 k*10+1,此时k=1101,那么k%6=3
对于k=111,下一位可能为0,即 k*10+0,此时k=1110,那么k%6=0
下一位可能为1,即 k*10+1,此时k=1111,那么k%6=1
我们发现k=1110时,k%6=0,即1110就是所求的倍数
从上面的演绎发现,用BFS是搜索 当前位数字 (除最高位固定为1),因为每一位都只有0或1两种选择,当k%n==0,即找到了所求倍数。但是因为所求的余数可能会非常大所以下面试着从余数和所求倍数的关系表示大数。
我们先将上面的bfs汉字描述写成如下的数字形式,便于发现规律
1%6=1 (k=1)
{
(1*10+0)%6=4 (k=10)
{
(10*10+0)%6=4 (k=100)
{
(100*10+0)%6=4 (k=1000)
(100*10+1)%6=5 (k=1001)
}
(10*10+1)%6=5 (k=101)
{
(101*10+0)%6=2 (k=1010)
(101*10+1)%6=3 (k=1011)
}
}
(1*10+1)%6=5 (k=11)
{
(11*10+0)%6=2 (k=110)
{
(110*10+0)%6=2 (k=1100)
(110*10+1)%6=3 (k=1101)
}
(11*10+1)%6=3 (k=111)
{
(111*10+0)%6=0 (k=1110) 有解
(111*10+1)%6=1 (k=1111) 由于前面有解,这个余数不存储
}
}
}
(a*b)%n = (a%n *b%n)%n
(a+b)%n = (a%n +b%n)%n
我们用同余模定理对上述的大数进行优化,如(原文博主的例子写错了一个数,应该把+1改成+0)当前步(110*10+0)%6=2
由同余模定理(110*10+0)%6=((110*10)%6+0)%6
=((110%6*10%6)%6)%6
=((2*10%6+0%6)%6)%6
=(2*10+0)%6
#include <iostream> #include <cstdio> using namespace std; int mod[524286];//这个数组大小,我不明白是怎么来的,还请路过的大佬解释下。 int main() { int n; int i; while(1){ scanf("%d",&n); if(!n) break; mod[1]=1%n; ///这里的前一步不是-1的上一步,是/2后的前一步。。 for(i=2;mod[i-1]!=0;i++){//利用同余模定理,从前一步的余数mod[i/2]得到下一步的余数mod[i] mod[i]=(mod[i/2]*10+i%2)%n; //mod[i/2]*10+i%2模拟了BFS的双入口搜索 //当i为偶数时,+0,即取当前位数字为0 。为奇数时,则+1,即取当前位数字为1 } i--; int pm=0; while(i) { mod[pm++]=i%2; //把*10操作转化为%2操作,逆向求倍数的每一位数字 i/=2; } while(pm) printf("%d",mod[--pm]); printf("\n"); } return 0; }