bzoj2242,洛谷2485----SDOI2011计算器(exgcd,qsm,bsgs模板)

本文深入探讨了BSGS算法,一种解决离散对数问题的有效方法,特别适用于求解形如a^x=b mod p的方程,其中p为质数。文章不仅提供了算法的理论基础,还给出了详细的代码实现,帮助读者理解和应用这一算法。

就是一道模板题!

这里再强调一下

BSGS

考虑方程\(a^x = b \pmod p\)

已知a,b,p\((2 \le p\le 10^9)\),其中p为质数,求x的最小正整数解

解法:

注意到如果有解,那么一定满足\(0<x<p\)

\(t=\lfloor \sqrt p \rfloor\)

那么一定有

\((a^t)^c=ba^d \pmod p\)

此时\(x=ct-d(0 \le d <t)\)

因为\[\frac{a^{ct}}{a^d} = b \pmod p\]

那么我们预处理一个\(a^d\),因为d的取值只有t个,所以可以先预处理,然后暴力枚举左边,看看有没有合法的解

不多说了
直接上代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#include<map>

using namespace std;

inline ll read()
{
  ll x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}

ll n,m;
ll mod;
map<ll,ll> mp;

ll qsm(ll i,ll j)
{
    ll ans=1;
    while (j)
    {
        if (j&1) ans=ans*i%mod;
        i=i*i%mod;
        j>>=1;
    }
    return ans;
}

ll exgcd(ll &x,ll &y,ll a,ll b)
{
    if (b==0)
    {
        x=1;
        y=0;
        return a;
    }
    ll cnt=exgcd(x,y,b,a%b);
    ll tmp =x;
    x=y;
    y=tmp-a/b*y;
    return cnt;
}

ll bsgs(ll a,ll b)
{   
    mp.clear(); 
    if (a%mod==0 && b==0) return 0;
    if (a%mod==0 && b!=0) return -1;
    //if (a==1 && b!=1) return -1;
    //if (a==1 && b==1) return 0;
    //==0) return -1;
    ll t = ceil(sqrt(mod));
    for (ll i=0;i<=t;i++) 
    {
        ll tmp = qsm(a,i)*b%mod;
        if (!mp[tmp]) mp[tmp]=i;
    }
    for (ll c=1;c<=t;c++)
    {
        ll cnt = qsm(a,c*t)%mod;
        if (mp[cnt])
        {
            //cout<<c*t<<endl;
            return c*t-mp[cnt];
        }
    }
    return -1;
}

int main()
{
  scanf("%d%d",&n,&m);
  if (m==1)
  {
     for (int i=1;i<=n;i++)
     {
     ll x,y;
     x=read(),y=read(),mod=read();
     printf("%lld\n",qsm(x,y));
     }
  }
  
  if (m==2)
  {
    for (int i=1;i<=n;i++)
      {
        ll a,b,c;
        ll x=0,y=0;
        a=read(),c=read(),b=read();
        ll gcd=exgcd(x,y,a,b);
        if (c%gcd!=0)
        {
            printf("Orz, I cannot find x!\n");
            continue;
        }
        ll tmp = b/gcd;
        x=x*c/gcd%tmp;
        x=(x%tmp+tmp)%tmp;
        printf("%lld\n",x);
       } 
  }
  //return 0;
  if (m==3)
  {
     for (int i=1;i<=n;i++)
     {
        ll a,b;
        a=read(),b=read(),mod=read();
        ll tmp = bsgs(a,b);
        if (tmp==-1)
          printf("Orz, I cannot find x!\n");
        else
          printf("%lld\n",tmp);
       }
  }
  return 0;
}

转载于:https://www.cnblogs.com/yimmortal/p/10160815.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值