题意:
求最小的Y,满足XY mod Z = K
高次同余方程,用hash做,套模板。。
参考:
二:http://blog.csdn.net/ivan_zjj/article/details/7597109
但是这题和上题有个不同点就是
这题的C没有限制条件,也就是说这题并没有规定C必须是质数。
思路:
还是用 babystep_gaintstep算法求解。但是这题并不能用POJ_2417的算法,直接套该
算法,下面简要说明一下不能用的原因。首先我们有必要归纳一下用babystep算法解题
的步骤: (1) 、求M = ceil( sqrt(C) ) ;(2) for(i=0;i<M;i++) hash( i , A^i ) ;(3) 求D = A^M
%C;(4) 、r = 1 ; for( i = 0 ; i < M ; i++ ) ex_gcd(r , C , x , y ) ; res = x * B % C ; jj = find( res)
如果找到了这时候的jj,则答案就是i*M+jj,如果没有找到,则res = res * D % C,继续循
环查找,如果最终都没有找到,则输出无解。 在上述的步骤中,如果题目中没有告诉我们
gcd(A , C) = 1,则我们上述的方法是错误的,原因就在于第4步,求res的时候。因为如果
我们无法保证gcd(A , C) = 1 ,也就不能保证gcd(r ,C) = 1(因为D=A^M, r = D^i),所有在
用 扩展欧几里得求出r*x + C*y = gcd(r,C ) 的一个解x0之后,原方程:r*x+C*y = B的解
x = x0 * B / gcd(r,C) + i*C / gcd(r,C) ,但是我们这个时候并不能计算出gcd(r,C),因为此时
的r本来就是经过取余之后得出的,并不能直接用来求gcd,因此我们上述的普通babystep
算法就会出错了。
这样我们就要换一种处理的方法了,这里介绍一种AC大牛博客上的一种“消因子”的方法,
具体内容请看这里:AC大牛。经过上面的分析我们很清楚接下去的处理应该从哪方面着
手,就是应该从不能求出gcd(r , C)入手。一种思想就是既然无法求, 那我每次只要保证
gcd(r, C) = 1那样就可以想普通babystep一样求解了,既然要保证gcd(r,C) =1 ,而
r = (A^M)^i,因此归根到底还是要求gcd( A , C ) = 1。下面就是从AC大牛博客上参考的“消因子”
法了,每次我们 都消去A,C的一个因子,然后对B,C, D进行如下的处理:B/=tmp;C/=tmp ;
D = D* A/tmp%C ,这样经过b轮的消因子之后,gcd(A,C) = 1, 接下去我们就可以用普通
的babystep求解出方程:A^x = B'( mod C' ) 的解 res1, 原方程的解就是 res = res1 + b。
下面给出这种方法正确的简要证明;一开始我们要求的方程是:A^x = B( mod C ),也就是
求一个最小的x,使得A^x + C*y = B,通过消因子, 我们不断在方程两遍消去gcd(A,C),这
样方程就可以变成 D*A^x1 + C'*y1 = B',很简单就可以证明上式中 x = x1 + b ; y = y1 的(只要
在方程的两边分别将消去的因子乘回去等式还是保持不变的)。这样我们的问题就转化为了
求x1和y1,即D*A^x1 = B'( mod C' ),此时gcd( A , C') = 1,这样我们就可以用普通的babystep
求出上述式子的解x1,同时也就求出了x,这样本题就解决了。
但是上述的方法还是有一个bug的,也就是说,我们用babystep求出的x1>=0,所以上述的
方法只能求出x >= b的解,这样我们自然就会想到如果有一个解x < b怎么办,上述方法就会出
先错误了,因此我们这里还需要改进。考虑b的最大值是多少,考虑每次我们消去的因子数都
最小也就是2,这样我们就可以得到b的最大值就是log(C),这样我们只要保证每次log(C)之内的
解都特判一下, 就不会出现我们刚才的问题了, 所以我们要在进行上述处理之前进行一次for
循环 ,特判0 - log(C)直接的x是否能成为解,接下去再用上述的“消因子”算法。
最后不得不佩服发明这种算法的人的神奇,将O(C)复杂度的判断,分两级判断将复杂度降低
到O( sqrt(C) ),所以就是为什么叫" babystep_gaintstep "了
#include <iostream>
#include <cstdio>
#include <cmath>
#define maxn 65535
using namespace std;
struct hash
{
int a,b,next;
}Hash[maxn*2];
int flg[maxn+66];
int top,idx;
void ins(int a,int b)
{
int k=b&maxn;
if(flg[k]!=idx)
{
flg[k]=idx;
Hash[k].next=-1;
Hash[k].a=a;
Hash[k].b=b;
return ;
}
while(Hash[k].next!=-1)
{
if(Hash[k].b==b)
return ;
k=Hash[k].next;
}
Hash[k].next=++top;
Hash[top].next=-1;
Hash[top].a=a;
Hash[top].b=b;
}
int find(int b)
{
int k=b&maxn;
if(flg[k]!=idx)
return -1;
while(k!=-1)
{
if(Hash[k].b==b)
return Hash[k].a;
k=Hash[k].next;
}
return -1;
}
int gcd(int a,int b)
{
return !b?a:gcd(b,a%b);
}
int exgcd(int a,int b,int &x,int &y)
{
int t,ans;
if(!b)
{
x=1;
y=0;
return a;
}
ans=exgcd(b,a%b,x,y);
t=x;
x=y;
y=t-a/b*y;
return ans;
}
int Inval(int a,int b,int n)
{
int x,y,e;
exgcd(a,n,x,y);
e=(long long)x*b%n;
return e<0?e+n:e;
}
int pow_mod(long long a,int b,int c)
{
long long ans=1;
a%=c;
while(b)
{
if(b&1)
{
ans=ans*a%c;
}
a=a*a%c;
b>>=1;
}
return ans;
}
int BabyStep(int A,int B,int C)
{
top=maxn;
++idx;
long long buf=1%C,D=buf,K;
int i,d=0,tmp;
for(i=0;i<=100;buf=buf*A%C,i++)
if(buf==B)
return i;
while((tmp=gcd(A,C))!=1)
{
if(B%tmp) return -1;
++d;
C/=tmp;
B/=tmp;
D=D*A/tmp%C;
}
int M=(int)ceil(sqrt((double)C));
for(buf=1%C,i=0;i<=M;buf=buf*A%C,++i)
ins(i,buf);
for(i=0,K=pow_mod((long long)A,M,C);i<=M;D=D*K%C,++i)
{
tmp=Inval((int)D,B,C);
int w=find(tmp);
if(tmp>=0&&w!=-1)
return i*M+w+d;
}
return -1;
}
int main()
{
int A,B,C;
while(~scanf("%d%d%d",&A,&C,&B),A||B||C)
{
B%=C;
int tmp=BabyStep(A,B,C);
if(tmp<0)
printf("No Solution\n");
else
printf("%d\n",tmp);
}
return 0;
}
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#define CC(m ,what) memset(m , what , sizeof(m))
typedef __int64 LL ;
LL A, B ,C ;
const int NN = 99991 ;
bool hash[NN] ;
int idx[NN] , val[NN] ;
void insert(int id , LL vv){
LL v = vv % NN ;
while( hash[v] && val[v]!=vv){
v++ ; if(v == NN) v-=NN ;
}
if( !hash[v] ){
hash[v] = 1;
val[v] = vv ; idx[v] = id ;
}
}
int find(LL vv){
LL v = vv % NN ;
while( hash[v] && val[v]!=vv){
v++ ;
if(v == NN) v-=NN ;
}
if( !hash[v] ) return -1;
return idx[v] ;
}
void ex_gcd(LL a , LL b , LL& x , LL& y){
if(b == 0){
x = 1 ; y = 0 ;
return ;
}
ex_gcd(b , a%b , x, y) ;
LL t = x ;
x = y;
y = t - a/b*y ;
}
LL gcd(LL a,LL b){
while( a%b != 0){
LL c = a ;
a = b ;
b = c % b ;
}
return b ;
}
LL baby_step(LL A, LL B , LL C){
LL ans = 1 ;
for(LL i=0;i<=50;i++){
if(ans == B) return i ;
ans = ans * A % C ;
}
LL tmp , d = 0 ;
LL D = 1 % C ;
while( (tmp=gcd(A,C)) != 1 ){
if(B % tmp) return -1 ;
d++ ;
B/=tmp ;
C/=tmp ;
D = D*A/tmp%C ;
}
CC( hash , 0) ; CC( idx, -1) ; CC(val , -1) ;
LL M = ceil( sqrt(C*1.0) ) ;
LL rr = 1 ;
for(int i=0;i<M;i++){
insert(i, rr) ;
rr = rr * A % C ;
}
LL x, y ;
for(int i=0;i<M;i++){
ex_gcd(D, C , x, y) ;
LL r = x * B % C;
r = (r % C + C) % C ;
int jj = find( r ) ;
if(jj != -1){
return LL(i)*M + LL(jj) + d ;
}
D = D * rr % C ;
}
return -1 ;
}
int main(){
while(scanf("%I64d %I64d %I64d",&A,&C,&B) == 3){
if(A+B+C == 0 ) break ;
LL res = baby_step(A,B,C) ;
if( res == -1 ){
printf("No Solution\n");
continue ;
}
printf("%I64d\n",res);
}
return 0 ;
}