求解一个最小的x满足给定的方程Bx == N (mod P)
使用baby_step_giant_step算法。也就是先小步后大步算法。
1、令x=i*m+j (m=ceil(sqrt(p))),
那么原式化为 B^(i*m)*B^j==N(MOD P)
B^j==N*B^(-i*m)(MOD P)---------->B^j==N*B^m^(-i)(MOD P)
2、先预处理B^0,B^1,B^2……B^(m-1),存入HASH表,我使用结构体排序然后二分查找,这一步就是baby_step,每次移动1
3、然后快速幂求出B^-m,枚举i,如果存在N*B^(-i*m)存在于HASH表中,说明存在解x=i*m+j,这一步为giant_step,每次移动m
注意以上解法是最基本的,只能对于gcd(B,P)==1,算法的时间复杂度是O(sqrt(P)*log(sqrt(P)))
样题:poj2417
模板:
///大步小步算法
struct baby///小步算法预存的结构体定义
{
long long b,j;
bool operator < (const baby &other)const{
if(b==other.b)return j0)
{
if(y&1)ans=(ans*x)%mod;
x=(x*x)%mod;
y>>=1;
}
return ans;
}
///小步预存的个数为m的结构体里面查找num
long long find(long long num,long long m)
{
long long l=0,r=m-1,ans=-1;
while(r>=l)
{
long long mid=(r+l)/2;
if(babyv[mid].b>=num){
if(babyv[mid].b==num)
ans=babyv[mid].j;
r=mid-1;
}
else l=mid+1;
}
return ans;
}
///B^x=N(modP)求解x,无解返回-1
long long babystep_giantstep(long long B,long long N,long long P)
{
long long m=ceil(sqrt(P)),ans=1;
for(long long j=0;j
poj2417代码:点击打开链接
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define Inf (1<<29)
#define LL long long
using namespace std;
const int MM=110;
const long long MOD=1000000007;
///大步小步算法
struct baby///小步算法预存的结构体定义
{
long long b,j;
bool operator < (const baby &other)const{
return b0)
{
if(y&1)ans=(ans*x)%mod;
x=(x*x)%mod;
y>>=1;
}
return ans;
}
///小步预存的个数为m的结构体里面查找num
long long find(long long num,long long m)
{
long long l=0,r=m-1;
while(r>=l)
{
long long mid=(r+l)/2;
if(babyv[mid].b==num)return babyv[mid].j;
else if(babyv[mid].b>num)r=mid-1;
else l=mid+1;
}
return -1;
}
///B^x=N(modP)求解x,无解返回-1
long long babystep_giantstep(long long B,long long N,long long P)
{
long long m=ceil(sqrt(P-1)),ans=1;
for(long long j=0;j
求解一个最小的x满足给定的方程Ax == B (mod C)
其中C任意,即C不一定是素数
算法 : 扩展小步大步攻击
扩展小步大步攻击:A ^ x = B (mod C)
1 : i = 0-> 100 if A^i mod C == B return i;///做这一步是第四步有一个n
2 : 消因子, 将A^x = B mod C 划为 d * A ^ (x – n) = B (modC)
3 : m = ceil (sqrt(C))
4 : 将 A ^ (x - n) 化为 A ^ (I * m + j)(原x 化为了 n + I * m + j)这里与小步大步攻击不同
5 : for j = 0 ->m hash(j,A ^ j mod C)
6 : for i = 0 ->m AA = B/(d * A ^ m ^i)
7 :在hash表中查找AA,若有,取AA对应的j,则答案为I * m + j + n
样题:poj3243 hdu2815
ps:参考点击打开链接有详细证明的方法
模板:
///扩展大步小步算法
struct baby///小步算法预存的结构体定义
{
long long b,j;
bool operator < (const baby &other)const{
if(b==other.b)return j0)
{
if(y&1)ans=(ans*x)%mod;
x=(x*x)%mod;
y>>=1;
}
return ans;
}
///小步预存的个数为m的结构体里面查找num
long long find(long long num,long long m)
{
long long l=0,r=m-1,ans=-1;
while(r>=l)
{
long long mid=(r+l)/2;
if(babyv[mid].b>=num){
if(babyv[mid].b==num)
ans=babyv[mid].j;
r=mid-1;
}
else l=mid+1;
}
return ans;
}
///A^x=B(modC)求解x,gcd(A,C)不一定等于1,无解返回-1
long long ex_babystep_giantstep(long long A,long long B,long long C)
{
for(long long i=0;i<=100;i++)///先在小于100的数里面测试
if(q_pow(A,i,C)==B%C)return i;
///消因子, 将A^x=B%C化为d*A^(x – n)=B%C
long long g,n=0,d=1;
while((g=gcd(A,C))!=1)
{
if(B%g)return -1;///无解
n++;
B/=g;
C/=g;
d=(d*A/g)%C;
}
///无扩展小步大步操作
long long m=ceil(sqrt(C)),ans=1;
for(long long j=0;j
poj3243点击打开链接
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define Inf (1<<29)
#define LL long long
using namespace std;
const int MM=110;
const long long MOD=1000000007;
///扩展大步小步算法
struct baby///小步算法预存的结构体定义
{
long long b,j;
bool operator < (const baby &other)const{
if(b==other.b)return j0)
{
if(y&1)ans=(ans*x)%mod;
x=(x*x)%mod;
y>>=1;
}
return ans;
}
///小步预存的个数为m的结构体里面查找num
long long find(long long num,long long m)
{
long long l=0,r=m-1,ans=-1;
while(r>=l)
{
long long mid=(r+l)/2;
if(babyv[mid].b>=num){
if(babyv[mid].b==num)
ans=babyv[mid].j;
r=mid-1;
}
else l=mid+1;
}
return ans;
}
///A^x=B(modC)求解x,gcd(A,C)不一定等于1,无解返回-1
long long ex_babystep_giantstep(long long A,long long B,long long C)
{
for(long long i=0;i<=100;i++)///先在小于100的数里面测试
if(q_pow(A,i,C)==B%C)return i;
///消因子, 将A^x=B%C化为d*A^(x – n)=B%C
long long g,n=0,d=1;
while((g=gcd(A,C))!=1)
{
if(B%g)return -1;///无解
n++;
B/=g;
C/=g;
d=(d*A/g)%C;
}
///无扩展小步大步操作
long long m=ceil(sqrt(C)),ans=1;
for(long long j=0;j
注意:K>=Z
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define Inf (1<<29)
#define LL long long
using namespace std;
const int MM=110;
const long long MOD=1000000007;
///扩展大步小步算法
struct baby///小步算法预存的结构体定义
{
long long b,j;
bool operator < (const baby &other)const{
if(b==other.b)return j0)
{
if(y&1)ans=(ans*x)%mod;
x=(x*x)%mod;
y>>=1;
}
return ans;
}
///小步预存的个数为m的结构体里面查找num
long long find(long long num,long long m)
{
long long l=0,r=m-1,ans=-1;
while(r>=l)
{
long long mid=(r+l)/2;
if(babyv[mid].b>=num){
if(babyv[mid].b==num)
ans=babyv[mid].j;
r=mid-1;
}
else l=mid+1;
}
return ans;
}
///A^x=B(modC)求解x,gcd(A,C)不一定等于1,无解返回-1
long long ex_babystep_giantstep(long long A,long long B,long long C)
{
for(long long i=0;i<=100;i++)///先在小于100的数里面测试
if(q_pow(A,i,C)==B%C)return i;
///消因子, 将A^x=B%C化为d*A^(x – n)=B%C
long long g,n=0,d=1;
while((g=gcd(A,C))!=1)
{
if(B%g)return -1;///无解
n++;
B/=g;
C/=g;
d=(d*A/g)%C;
}
///无扩展小步大步操作
long long m=ceil(sqrt(C)),ans=1;
for(long long j=0;j=Z){puts("Orz,I can’t find D!");continue;}
long long ans=ex_babystep_giantstep(X,K,Z);
if(ans==-1)puts("Orz,I can’t find D!");
else printf("%I64d\n",ans);
}
return 0;
}
给定k,m,newx,其中m是素数,求出满足x^k mod m = newx 所有 x 的值
预备:
a、模mod的群G的元的阶的定义:a^m%mod==e的最小整数m叫做元a的阶
b、原根(本原元素)的定义:a^phi(m)%m==e,phi(m)是a的阶,则称a是模m的一个原根
原根的性质:{1,2,...,m-1} = {g,g^2,...,g^(m-1)}其中g是原根
原根的判定定理(欧拉定理):p(大于2)是一个素数,a是本原元素当且仅当a的(p-1)╱q次方(模p)不等于1,q是p-1的所有因子
求解问题的算法步骤如下
1) 先暴力求m的原根g
2) 大步小步求g^t = newx mod m
3) 则g^(t+v*m1) = newx mod m, m1 = p - 1
4) 设x = g^u mod p, x^k = (g^u)^k = g^(uk) = g^(t+v*m1)
化成uk+vm=t,可以用扩展欧几里得求得
样题:hdu3930 点击打开链接
参考自点击打开链接
代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
long long cnt=0;
long long p[2000001];
bool isprime[2000001];
///求a*b%c,因为a,b很大,所以要先将b写成二进制数
long long mul_mod(long long a, long long b, long long mod )
{
long long ans = 0, d = a % mod;
while( b )
{
if( b & 1 )
{
ans += d;
if( ans > mod )ans -= mod;
}
d += d;
if( d > mod )d -= mod;
b >>= 1;
}
return ans;
}
void init()
{
isprime[0]=isprime[1]=true;
for(int i=2; i<=1000000; i++)
{
if(isprime[i])continue;
p[cnt++]=i;
for(int j=i+i; j<=1000000; j+=i)
isprime[j]=true;
}
}
long long num=0;
long long f[200];
void factor(long long n)
{
num=0;
for(long long i=0; i1)f[num++]=n;
}
///扩展大步小步算法
struct baby///小步算法预存的结构体定义
{
long long b,j;
bool operator < (const baby &other)const
{
if(b==other.b)return j0)
{
//if(y&1)ans=(ans*x)%mod;
if(y&1)ans=mul_mod(ans,x,mod);
//x=(x*x)%mod;
x=mul_mod(x,x,mod);
y>>=1;
}
return ans;
}
///小步预存的个数为m的结构体里面查找num
long long find(long long num,long long m)
{
long long l=0,r=m-1,ans=-1;
while(r>=l)
{
long long mid=(r+l)/2;
if(babyv[mid].b>=num)
{
if(babyv[mid].b==num)
ans=babyv[mid].j;
r=mid-1;
}
else l=mid+1;
}
return ans;
}
///A^x=B(modC)求解x,gcd(A,C)不一定等于1,无解返回-1
long long ex_babystep_giantstep(long long A,long long B,long long C)
{
for(long long i=0; i<=100; i++) ///先在小于100的数里面测试
if(q_pow(A,i,C)==B%C)return i;
///消因子, 将A^x=B%C化为d*A^(x – n)=B%C
long long g,n=0,d=1;
while((g=gcd(A,C))!=1)
{
if(B%g)return -1;///无解
n++;
B/=g;
C/=g;
//d=(d*A/g)%C;
d=mul_mod(d,A/g,C);
}
///无扩展小步大步操作
long long m=ceil(sqrt(C+0.0)),ans=1;
for(long long j=0; j=num)return true;
return false;
}
long long find_g(long long mod)
{
factor(mod-1);
for(long long g=2;; g++)
if(judge(g,mod))return g;
}
vectorres;
int main()
{
init();
long long Case=1;
long long newx,k,m;
while(scanf("%I64d%I64d%I64d",&k,&m,&newx)!=EOF)
{
printf("case%I64d:\n",Case++);
long long u,v;
long long g=find_g(m);
long long t=ex_babystep_giantstep(g,newx,m);
long long GCD=extended_euclid(k,m-1,u,v);
if(t%GCD||newx>=m)puts("-1");
else
{
res.clear();
long long up=t/GCD;
long long down=(m-1)/GCD;
u=(u*up%down+down)%down;
for(long long i=0; i