1. 程式人生 > >bzoj2242,洛谷2485----SDOI2011計算器(exgcd,qsm,bsgs模板)

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

就是一道模板題!

這裡再強調一下

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;
}