poj2417大步小步法

xiaoxiao2021-02-28  55

当n是素数时

a^x≡b (mod n)

令x=im+j,m=ceil(sqrt(n))   0<=i,j<m

a^j≡b*(a^(-m))^i    mod(n)

用hash表存储a^0,a^1……a^(m-1),枚举i,找是否存在对应的j,存在即有解

n 不是素数之所以不成立是因为 ( a,n )!=1 导致逆元不存在。

a^x-kn=b;

当n不是素数时,设gcd=gcd(a,n),若gcd不能整除b,则无解

否则两端同时除以gcd,重复此步骤

#include<string.h> #include<stdio.h> #include<iostream> #include<cmath> #include<algorithm> using namespace std; struct node{ int num; long long val; }a[1000000]; bool cmp(node x,node y){ return x.val==y.val?x.num<y.num:x.val<y.val; } int mod,m,cnt; int pow_mod(int a,int b){ long long t=a,res=1; while(b){ if(b&1) res=res*t%mod; t=t*t%mod; b>>=1; } return res; } int find(int n){ int l=0,r=cnt,mid; while(r>l+1){ mid=(l+r)>>1; if(a[mid].val<=n) l=mid; else r=mid; } if(a[l].val==n) return a[l].num; else return -1; } int main(){ int p,b; long long n; while(scanf("%d%d%I64d",&p,&b,&n)!=EOF){ if(n==1){ printf("0\n"); continue; } mod=p; m=ceil(sqrt(1.0*p)); int ni=pow_mod(pow_mod(b,p-2),m); a[0].val=1; a[0].num=0; for(int j=1;j<m;j++){ a[j].val=a[j-1].val*b%p; a[j].num=j; } sort(a,a+m,cmp); cnt=1; for(int j=1;j<m;j++){ if(a[j].val!=a[cnt-1].val){ a[cnt++]=a[j]; } } int i,j=-1; for(i=0;i<=m;i++){ j=find(n); if(j!=-1) break; n=n*ni%p; } if(j==-1){ printf("no solution\n"); continue; } long long ans=i*m+j; printf("%I64d\n",ans); } }

转载请注明原文地址: https://www.6miu.com/read-97186.html

最新回复(0)