baby step giant step

我们研究一些小问题

先研究对于a^L mod c = b(已知a,b,c,   c为质数,求最小的L)的情况。

那么对于L < C的情况:

设m = [sqrt(c)],L = k*m + j;

则(a^(k*m))*(a^j) mod c = b;

baby step:

我们可以知道j < m

我们预处理出a^0 ~ a^(m-1) % c,并且将他们堆入Hash中。(O(m))

giant step:

我们设a^(-m) = p

则(a^j) mod c = b * (p^k) mod c;

我们枚举k.

若b*(p^k) mod c存在于Hash表当中,那代表我们已经找到答案了,可以直接退出。

O(m)

                总体复杂度O(m)

练习题:poj2417

接下来是比较难的问题。

给定a,b,c(只有大小限制), 求最小的L使得a^L mod c = b

这题没有了上题的a,b,c互质的情况。

我们可以进行一些消元。

设a^L = k * c + b;

则a * a^(L-1) = k  * c + b;

设gcd(a,c) = d

那么(a/d) * a^(L - 1) = k * (c / d) + b/d;

若b mod d <> 0,那么无解。

否则我们记录一个D = π(a/d),d = a除的次数。

那么到最后我们就可以得到D * a^j mod c' = b'

并且此时a,b,c互质了。

我们直接套用上面的普通解法即可。

练习题:spoj_MOD


spoj_Mod

#include
   
   
    
    
#include
    
    
     
     
#include
     
     
      
      

using namespace std;

const int has1 = 57601;

typedef long long LL;

int A[3][has1],N;

int gcd1(int a,int b) {return b ? gcd1(b,a % b) : a;}

int gcd(int a,int b,int &x,int &y)
{
	if (!b) {x = 1,y = 0;return a;}
	int v = gcd(b,a % b,x,y),t = y;
	y = x - (a / b) * y,x = t;
	return v;
}

int ex_gcd(int a,int b,int c)
{
	int x,y,n = gcd(a,b,x,y);
	if (!c % n) return -1;
	x = x * LL(c / n) % N;
	int k = b / n;
	if (k < 0) k = -k;
	if (x < 0) x += ((-x) / k + 1) * k;
	return x;
}

int hash(int a,int b)
{
	int p = a % has1;
	while (A[0][p] && A[0][p] != a) p = A[2][p];
	if (A[0][p]) return A[1][p];
	if (b) 
	{
		A[0][p] = a,A[1][p] = b;
		A[2][p] = (p + 1) % has1;
	}
	return 0;
}

void Work(int a,int b)
{
	memset(A,0,sizeof A);
	int tmp = 1;
	for(int i = 0;i < 31;i ++) if (tmp == b) {printf("%d\n",i);return;} else tmp = tmp * LL(a) % N;
	int d = 0,D = 1,k,z,y;
	b %= N;
	while ((k = gcd1(a,N)) != 1)
	{
		if (b % k) {printf("No Solution\n");return;}
		b /= k,N /= k,d ++,D = D * LL(a) / k % N;
	}
	int m = sqrt((double)(N));tmp = 1;
	for(int i = 1;i <= m;i ++) hash(tmp,i),tmp = tmp * LL(a) % N;
	int Nt = tmp;
	tmp = 1;
	for(int i = 0;i <= m;i ++)
	{
		int p = ex_gcd(D * LL(tmp) % N,N,b),l;
		tmp = tmp * LL(Nt) % N;
		if (p == -1 || !(l = hash(p,0))) continue;
		{printf("%d\n",i * m + l - 1 + d);return;}
	}
	printf("No Solution\n");
}

int main()
{
	int a,b;
	while (scanf("%d %d %d", &a, &N, &b) != EOF && ((a | N) | (b))) Work(a,b);
}

     
     
    
    
   
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值