bzoj3122 随机数生成器 BSGS+费马小定理求逆元

本文深入讲解了BSGS(Baby Steps Giant Steps)算法,并通过一道数论难题演示了其应用过程。文章提供了简洁易懂的代码实现,利用费马小定理通过快速幂求逆元,帮助读者掌握这一高效解决离散对数问题的方法。

这里写图片描述

这道题应该算是数论里面比较难的一道题,我顺便借此学了BSGS(Baby Steps Giant Steps),又称力拔盖世算法(手动滑稽).刚开始看到这道题只能感到深深的无助,完全不会做…对于一道数论题如果不会做的话,大家还是可以尝试很多特判骗分的,这道题就有很多特判.从小角度切入,深入了解问题,往往是很重要的.
由于不知道怎么打出一堆数学符号,所以很难与大家分享我的题解。我在网上找了另一个人的博客,他这道题讲的很清晰,我学BSGS也是从他那里学来的,希望大家能够学会。这篇博客就当提供一段简洁明了,逻辑清晰的代码(真的挺短,只用了费马小定理通过快速幂求逆元).
BSGS:http://blog.youkuaiyun.com/clove_unique/article/details/50740412
bzoj3122:http://blog.youkuaiyun.com/clove_unique/article/details/50776001

#include<stdio.h>
#include<map>
#include<cmath>
using namespace std;
typedef long long dnt;
map<dnt,dnt> has;
dnt p,a,b,x1,t,T,ny,nia,ans,oops;
inline const dnt read(){
    register dnt f=1,x=0;
    register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
inline dnt pow(dnt base,dnt tmp){
    dnt a=1;
    while(tmp){
      if(tmp&1) a=a*base%p;
      base=base*base%p;
      tmp=tmp>>1;
    }
    return a;
}
inline dnt BSGS(dnt a,dnt b){
    dnt m=ceil(sqrt(p)),am=pow(a,m),mul=1,val=b%p;
    has.clear();
    has[val]=0;
    for(dnt j=1;j<=m;j++){
        mul=mul*a%p;
        val=mul*b%p;
        has[val]=j;
    }
    mul=1;
    for(dnt i=1;i<=m;i++){
       mul=mul*am%p;
       if(has[mul]) return i*m-has[mul]+1;
    }
    return -1;
}
int main(){
    T=read();
    while(T--){
      p=read(),a=read(),b=read(),x1=read(),t=read();
      if(t==x1) {printf("1\n");continue;}
      if(!a){
         if(b!=t) printf("-1\n");
         else printf("2\n");
         continue;
      }
      if(a==1){
         if(!b) printf("-1\n"); 
         else{
            ny=pow(b,p-2);
            ans=((t-x1)%p+p)%p*ny%p;
            printf("%lld\n",ans+1);
         }
         continue;
      }
      nia=pow(a-1,p-2);
      oops=(t+b%p*nia%p)%p*pow(x1+b%p*nia%p,p-2)%p;
      printf("%lld\n",BSGS(a,oops));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值