[TJOI2007] 可爱的质数/【模板】BSGS
BSGS 可以在 $O( \sqrt{ p } ) $ 的复杂度下求解:
$$ a ^ x \equiv b \pmod {p}$$
其中 $a \perp p$,方程的解 $x$ 满足 $0 \le x < p$。
首先我们假设 $x = A \left\lceil \sqrt{ p } \right\rceil - B $,其中 $0 \le A , B \le \left\lceil \sqrt{ p } \right\rceil$,于是就有:
$$ a ^ { A \lceil \sqrt{ p } \rceil - B } \equiv b \pmod { p }$$
变形一下就能得到:
$$ a ^ { A \lceil \sqrt{ p } \rceil } \equiv b a ^ B \pmod { p }$$
右边的值我们可以通过枚举得到所有可能的值,并将其存入 Hash 表中,左边再枚举 $A$,发现表中若有相同的值,说明我们找到了一个可能的解。
最后时间复杂度 $O ( \sqrt { p } )$,用 map
的话就是 $O( \sqrt { p } \log p )$。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| #include<iostream> #include<cstdio> #include<cmath> #include<map> #define ll long long using namespace std; namespace Ehnaev{ inline ll read() { ll ret=0,f=1;char ch=getchar(); while(ch<48||ch>57) {if(ch==45) f=-f;ch=getchar();} while(ch>=48&&ch<=57) {ret=(ret<<3)+(ret<<1)+ch-48;ch=getchar();} return ret*f; } inline void write(ll x) { static char buf[22];static ll len=-1; if(x>=0) {do{buf[++len]=x%10+48;x/=10;}while(x);} else {putchar(45);do{buf[++len]=-(x%10)+48;x/=10;}while(x);} while(len>=0) putchar(buf[len--]); } }using Ehnaev::read;using Ehnaev::write;
const ll N=1e6;
ll p,a,b,ans,sp,tot; ll nxt[N+5],val[N+5]; map<ll,ll> head;
inline ll Pow(ll b,ll p,ll mo) { ll r=1;while(p) {if(p&1) r=r*b%mo;b=b*b%mo;p>>=1;}return r; }
inline void Addhash(ll x,ll v) { val[++tot]=v; if(head.find(x)!=head.end()) nxt[tot]=head[x]; head[x]=tot; }
inline void Findhash(ll x,ll v) { if(head.find(x)!=head.end()) { for(ll i=head[x];i;i=nxt[i]) { ll tmp=v*sp-val[i]; if(tmp>=0) {if(ans<0||tmp<ans) ans=tmp;} } } }
int main() {
p=read();a=read();b=read();sp=ceil(sqrt(p));
ll r=b%p; for(ll i=0;i<=sp;i++) {Addhash(r,i);r=r*a%p;}
ll sr=Pow(a,sp,p);r=1;ans=-1; for(ll i=0;i<=sp;i++) { Findhash(r,i);r=r*sr%p; }
if(ans>=0) write(ans); else printf("no solution");
return 0; }
|