BSGS
const int MOD=76543; ll hs[MOD],head[MOD],nxt[MOD],id[MOD],top; void insert(ll x,int y){ ll k=x%MOD; hs[++top]=x,id[top]=y,nxt[top]=head[k],head[k]=top; } ll find(int x){ ll k=x%MOD; for(int i=head[k];i!=-1;i=nxt[i]) if(hs[i]==x)return id[i]; return -1; } ll bsgs(ll a,ll b,ll n) { //a^x=b mod n a%=n,b%=n; //取最小 if(!a)return -1; if(b==1)return 0; me(head,-1);top=0; int m=sqrt(1.0*n),j; ll x=1,p=1,i; for(i=0;i<m;i++,p=p*a%n)insert(p*b%n,i); for(i=m;;i+=m){ if((j=find(x=x*p%n))!=-1) return i-j; if(i>n) break; } return -1; }
EXBSGS
void exgcd(ll a,ll b,ll &x,ll &y){if(!b)x=1,y=0;else exgcd(b,a%b,y,x),y-=(a/b)*x;} const int mod=100003; struct node{ int nxt[mod],val[mod],id[mod],cnt,hd[mod]; void init(){me(nxt,0),me(val,0),me(id,0),me(hd,0),cnt=0;} void insert(ll x,int d){ int st=x%mod; for(int i=hd[st];i;i=nxt[i]){if(val[i]==x)return;} val[++cnt]=x,nxt[cnt]=hd[st],id[cnt]=d,hd[st]=cnt; } int find(ll x){ int st=x%mod; for(int i=hd[st];i;i=nxt[i])if(val[i]==x) return id[i]; return -233; } }ha; int BSGS(ll a,ll b,ll c){ //a^x=b mod c int up=(int)floor(sqrt(1.0*c-1))+1; ll ni=0,yy=0; exgcd(ksm(a,up,c),c,ni,yy); ni=(ni%c+c)%c;//warning!!! 必须变成正数 ll kk=1; for(int i=0;i<=up-1;i++){ ha.insert(kk,i); kk=(kk*a)%c; } ll bb=b; for(int i=0;i<=up;i++){ int kk=ha.find(bb); if(kk>=0) return i*up+kk; bb=(bb*ni)%c;//不断找逆元 递推就可以 } return -233; } int EXBSGS(ll A,ll B,ll C){// A^x=B mod C int num=0,yC=C,yB=B,yA=A; ll ji=1;int ret=-233;bool flag=false; while(true){ int g=__gcd(A,C); if(g==1) break; if(B%g){flag=true;break;} B/=g,C/=g,ji=(ji*A/g)%C; num++; } for(int i=0;i<=num;i++){ ll kk=ksm(yA,i,yC); if(kk%yC==yB) return i; } if(!flag){ ll ni,yy; exgcd(ji,C,ni,yy); ni=(ni%C+C)%C;//warning!!! 必须变成正数 ll NB=(B*ni)%C; ret=BSGS(A,NB,C); } if(ret>=0) return ret+num;return -233; }
二次剩余
原理:
#define random(a,b) (rand()%(b-a+1)+a) struct node{ll x,y;}; ll p,w; node operator *(node a,node b){ node ans; ans.x=(a.x*b.x%p+a.y*b.y%p*w%p)%p; ans.y=(a.x*b.y%p+a.y*b.x%p)%p; return ans; } node operator^(node a,ll b){ node ans={1,0}; for(;b;b>>=1,a=a*a)if(b&1)ans=ans*a; return ans; } ll legender(ll a){ ll ans=ksm(a,p-1>>1,p); if(ans+1==p)return -1; return ans; } ll sovle(ll n){ ll a; if(p==2)return n; if(legender(n)==-1)return -1; srand((unsigned)time(NULL)); while(true){ a=random(0,p-1); w=(a*a%p-n+p)%p; if(legender(w)==-1)break; } node res={a,1};// a+sqrt(w) res=res^(p+1>>1); return res.x; } int main(){ ll n; cin>>p>>n; n%=p; ll ans=sovle(n); if(ans==-1)return o("No Solution"); ll res=p-ans; if(res>ans)swap(res,ans); if(ans*2!=p)cout<<res<<" "; o(ans); }