1. 程式人生 > >Luogu4195 【模板】exBSGS(exBSGS)

Luogu4195 【模板】exBSGS(exBSGS)

void long mes gcd read 部分 \n solution algo

  如果a和p互質,用擴歐求逆元就可以直接套用普通BSGS。考慮怎麽將其化至這種情況。

  註意到當x>=logp時gcd(ax,p)是一個定值,因為這樣的話每個存在於a中的質因子,其在ax中的出現次數一定比在p中的多。

  於是對x<logp的情況暴力驗證。對x>=logp的情況,設d=gcd(ax,p),剩下的問題變為求ax/d≡b/d(mod p/d),這裏ax和p/d顯然就是互質的了。

  要求解這個方程,顯然不能把d直接乘過去(好像也說不清為啥)。首先b%d>0時無解。然後考慮從ax中分離一部分,使該部分能整除d,再將該部分除以d後移到式子右邊。直接分離的話會爆long long,每次分離一個a即可。剩下的就是普通BSGS了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
#define ll long long
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
    int x=0,f=1;char c=getchar();
    
while (c<0||c>9) {if (c==-) f=-1;c=getchar();} while (c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int a,p,b; map<int,int> f; void exgcd(int a,int b,int &x,int &y) { if (b==0) { x=1,y=0; return; } exgcd(b,a
%b,x,y); int t=x;x=y;y=t-a/b*x; } int inv(int a) { int x,y;exgcd(a,p,x,y); x=(x%p+p)%p; return x; } int BSGS(int a,int b,int p) { int block=sqrt(p),t=1;//cout<<a<<‘ ‘<<b<<‘ ‘<<p<<endl; f.clear(); for (int i=0;i<block;i++) { if (f.find(t)==f.end()) f[t]=i; if (t==b) return i; t=1ll*t*a%p; } int v=t; for (int i=1;i<=(p-1)/block;i++) { if (f.find(1ll*b*inv(t)%p)!=f.end()) return i*block+f[1ll*b*inv(t)%p]; t=1ll*t*v%p; } return -32; } int main() { #ifndef ONLINE_JUDGE freopen("exbsgs.in","r",stdin); freopen("exbsgs.out","w",stdout); #endif a=read(),p=read(),b=read(); while (a) { if (p==1) printf(b==0?"0\n":"No Solution\n"); else if (b==1) printf("0\n"); else { int t=1,ans=0; for (int i=1;i<=31;i++) { t=1ll*t*a%p; if (t==b) {ans=i;break;} } if (!ans) { int u=gcd(p,t); if (b%u==0) { //a^x/u=b/u (%p/u) int P=p;b/=u;p/=u; for (int i=1;i<=31;i++) if (P==p) {ans=i-1;break;} else { int u=gcd(a,P); b=1ll*b*inv(a/u)%p; P/=u; } ans+=BSGS(a,b,p);ans=max(ans,0); } } if (ans) printf("%d\n",ans); else printf("No Solution\n"); } a=read(),p=read(),b=read(); } return 0; }

Luogu4195 【模板】exBSGS(exBSGS)