[SDOI2011]计算器(同余相关)
Solution
k==1:快速幂
k==2:扩展欧几里得
k==3:BSGS
BSGS:
对于
$$y^x≡z\pmod{m}$$
设 $m=\sqrt{p}$ 上取整
则 $x$ 可表示为 $i*m-j$ ($0<=j<=m$)
于是
$$y^{i*m}≡z*y^j\pmod{m}$$
我们把 $0<=j<=m$ 的 $z*y^j\pmod{m}$ 存入哈希表
再依次查找 $1<=i<=m$ 的 $y^{i*m}\pmod{m}$ 再哈希表中是
否存在,若存在,则找到了最小的 $x$
Code
#include <cstdio> #include <cstdlib> #include <map> #include <cmath> #include <algorithm> #define ll long long using namespace std; ll y,z,p; int T,k; ll qpow(ll x,ll y,ll p) { ll ans=1; while(y) { if(y&1) ans=ans*x%p; x=x*x%p,y>>=1; } return ans; } ll exgcd(ll a,ll b,ll &x,ll &y) { if(b==0) { x=1,y=0; return a; } ll r=exgcd(b,a%b,y,x); y-=(a/b)*x; return r; } int main() { scanf("%d%d",&T,&k); while(T--) { scanf("%lld%lld%lld",&y,&z,&p); if(k==1) printf("%lld\n",qpow(y,z,p)); else if(k==2) { ll n,m; ll c=exgcd(y,p,n,m); if(z%c) puts("Orz, I cannot find x!"); else { n*=(z/c); ll mod=(p/c); printf("%lld\n",(n%mod+mod)%mod); } } else if(k==3) { if(y%p==0) { if(z) puts("Orz, I cannot find x!"); else puts("0"); continue; } map <ll,int> hs; ll sq=ceil(sqrt(p)),now=z%p,f=qpow(y,sq,p); for(int i=0;i<=sq;i++) { hs[now]=i+1; now=now*y%p; } bool end=false; now=1; for(ll i=1;i<=sq;i++) { now=now*f%p; if(hs.count(now)) { printf("%lld\n",(i*sq-hs[now]+1+p)%p); end=true; break; } } if(!end) puts("Orz, I cannot find x!"); } } return 0; }

浙公网安备 33010602011771号