【模板】(朴素BSGS板子)POJ2417 (高次同余方程)

朴素BSGS

基础知识预备:扩展欧几里得算法,hash表(或map代替,但显然hash效率更高),费马小定理

算法:baby step giant step(btgt,大小步算法)

算法深层思想:分块

  B^L == N (mod P)

题目简述:给定B,N,P,解出最小L(b p互质(原题P为质数))

由于费马小定理我们可以证明得到L的范围是在0到p-1之间的 于是如果我们直接从0开始枚举,原地爆炸(--)

欢迎来到分块的骚操作

设u=sqrt(p) 我们可以将L表示为L=iu+v (v=v%u) (i=p/u) 代入原式B^(iu+v) == N (mod p) 于是乎我们将第一个块的所有内容全部塞到hash(map)里面 塞进了B^0 B^1 B2....B(u-1)(大小步中的小步)

然后我们开一个数D1=Bu D2=B(2u)....D(u-1)==B(u(u-1)) 然后对于D有如下公式

D^(i)y == N (mod P) 

(y为之前算出的某个B好好想想为什么用这样的方式就可以表示出p-1内的所有数了,本质是分块)

怎么判断出这个解呢?显然用上exgcd了,然后得到的解在hash里面一查就好,如果有,由于我们是从小到大找,那么这就是最小解,答案就是d*i+y。如果扫到最后还是没有找到解,那么这个方程就无解了

不想写hash,不想写hash,不想写hash,比较懒,于是我直接用的map(事实上效率相差度很高,不要学我(日后再加上hash的代码))

时间复杂度(msqrt(n))(m为询问次数)(如果用map会再徒乘根号n的时间复杂度)

时间复杂度(msqrt(n))(m为询问次数)(如果用map会再徒乘根号n的时间复杂度)

#include<iostream>
#include<vector>
#include<map>
#include<cstdio>
#include<cmath>
typedef long long ll;
using namespace std;
ll p,b,a;
map<ll,ll>ma;
map<ll,bool>mm;
ll exgcd(ll c,ll d,ll &x,ll &y)
{
if(!d){x=1; y=0; return c; }
ll r=exgcd(d,c%d,x,y);
ll tmp=x; x=y; y=tmp-(c/d)*y;
return r;
}

void bgstep()
{
ll bb=1,ks=ceil(pow(p,0.5));
for(ll i=0;i<ks;i++)
{
    if(!mm[bb]) { ma[bb]=i; mm[bb]=true;  }
    bb=bb*a%p;
}
ll d=1;ll gcd,x,y;
for(ll i=0;i<=ks-1;i++)
{
    gcd=exgcd(d,p,x,y);
    x=(b/gcd *x%p+p)%(p/gcd);
    if(mm[x]){ printf("%lld\n",ma[x]+i*ks);return ; }
    d=d*bb%p;
}
 printf("no solution\n");
}

int main()
{
while(scanf("%lld%lld%lld",&p,&a,&b)!=EOF) 
{
ma.clear();
mm.clear();
bgstep();
}
}

 

posted @ 2018-03-20 18:24  Newuser233  阅读(6)  评论(0)    收藏  举报