咕了这么久,也该补上了……
拔山盖世×扩展拔山盖世敬上:
$A^xequiv Bpmod{C}$
上面这个就是北上广深的应用,一般的北上广深只能应用于$C$为质数的时候,扩展应用于$C$为任何数时。
先来看一般的类型:
由费马小定理可知:若$A$不是$C$的倍数,则有:$A^{C-1}equiv1pmod{C}$。还有显然的$A^0equiv1pmod{C}$
所以我们的暴力只需要跑$O_{(C)}$即可。
考虑一个神仙的优化:我们可以设$m=ceil(sqrt{C})$,则一定有:$x=i*m-j$
令$jin(0,m)$ ,则原式可变为:$A^{i*m}equiv B*A^jpmod{C}$
所以我们可以先与处理出$A^j$然后枚举$i$即可复杂度为:$O_{(m)}$
(先不放代码ヾ(o◕∀◕)ノヾ)
再来看一下扩展拔山盖世:
引理:如果有$dmid A$且$dmid B$且$dmid C$,则有:$A^{x-1}*frac{A}{d}equiv frac{B}{d}pmod{frac {C}{d}}$
那么这样下去,我们可以每次令$d=gcd(A,{mod后面的数})$直到$d=1$为止。
然后再跑拔山盖世就行啦,正式上代码:
//A^x≡B(mod C) #include<bits/stdc++.h> using namespace std; #define int long long inline int read() { int f=1,w=0;char x=0; while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();} while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();} return w*f; } map<int,int> mp; inline int gcd(int a,int b){return !b?a:gcd(b,a%b);} inline int EXBSGS(int A,int B,int C) { if(B==1) return 0; int d,cnt=0,k=1; while((d=gcd(A,C))^1) { if(B%d) return -1; B/=d;C/=d;++cnt; k=(k%C*(A/d)%C)%C; if(k==B) return cnt; } mp.clear(); int m=sqrt(C)+1,now=1; for(int i=0;i<m;i++) { mp[(now*B)%C]=i; now=((now%C)*(A%C))%C; } k=((k%C)*(now%C))%C; for(int i=1;i<=m;i++) { if(mp[k]) return ((i%C)*(m%C)-mp[k]+cnt+C)%C; k=((k%C)*(now%C))%C; } return -1; } main(){ int A,B,C; scanf("%lld%lld%lld",&A,&C,&B); while(A&&B&&C) { int ans=EXBSGS(A,B,C); if(ans==-1) printf("No Solution "); else printf("%lld ",ans); scanf("%lld%lld%lld",&A,&C,&B); } }