bzoj2242,洛谷2485----SDOI2011計算器(exgcd,qsm,bsgs模板)
阿新 • • 發佈:2018-12-22
就是一道模板題!
這裡再強調一下
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; }