传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2242
文献:
http://blog.csdn.net/nike0good/article/details/9171173
http://blog.csdn.net/acm_cxlove/article/details/7831793
http://blog.csdn.net/nike0good/article/category/1469561
http://blog.csdn.net/a601025382s/article/details/11745787
http://hi.baidu.com/bearjie_leo/item/1de55e45d19bd49b823ae17b
第一问快速幂
第二问扩展欧几里德解线性同余方程 ax=b(mod n)
第三问高次同余方程a^x=b(mod n),Baby Step Giant Step算法::
解高次同余方程a^x=b(mod n) n为质数
设x=i*m+j m=ceil(sqrt(n))
则a^im*a^j=b(mod n)
==>(a^m)^i*a^j=b(mod n)
求a^m模n的乘法逆元v=a^(n-m-1){
乘法逆元:若ax=1(mod n),则称a模n的乘法逆元是x
性质:K/x mod n = K*a mod n (将就着看,不是很科学)
证明v=a^(n-m-1)是乘法逆元:{
由费马小定理得a^(n-1)=1(mod n)
则a^m*a^(n-m-1)=1(mod n)
所以v=a^(n-m-1)
}
}
所以(a^m)^i*a^j=b(mod n)
==>a^j=b*v^i(mod n)
枚举j=0 ->m-1 将a^j mod n存入hash表
枚举i=0 ->m-1 每次计算 b*v^i mod n,若计算过程中发现b*v^i mod n在hash表中出现过,返回i*m+j
这样就解完了复杂度O(sqrt(n))当然这是你hash写得好才行,蒟蒻用map,或者二分判断,复杂度O(sqrt(n)logn)
复杂度O(sqrt(n)log(n))来自快速幂和hash
AC代码:
/* ID:zky OJ:BZOJ Index:2242 Language:C++ */ #include<map> #include<set> #include<cmath> #include<cstdio> #include<iostream> #include<algorithm> using namespace std; typedef long long lld; map<lld,lld>hash; lld t,k; lld x,y,z,p; lld power(lld a,lld b,lld n){ lld s=1; while(b){ if(b&1) s=(s*a)%n; a=(a*a)%n; b=b>>1; } return s; } void work1(){ cout<<power(y,z,p)<<endl; } lld gcd(lld a,lld b){ if(!b)return a; return gcd(b,a%b); } void exgcd(lld a,lld b,lld &x,lld &y){ if(!b){ x=1; y=0; return; } exgcd(b,a%b,x,y); lld t=x; x=y; y=t-a/b*y; } void work2(){ //yx=z(mod p) lld d=gcd(y,p); if(z%d){ cout<<"Orz, I cannot find x!"<<endl; return; } lld r,s; exgcd(y,p,r,s); r=r*z/d; r=(r+p)%p; while(r<0)r+=p; //while(r<0)r+=p; cout<<r<<endl; } void work3(){ y%=p;z%=p; //a^x=b(mod n)=>y^x=z(mod p) if(!y&&!z){cout<<"1"<<endl;return;} if(!y){cout<<"Orz, I cannot find x!"<<endl;return;} lld m=ceil(sqrt(p)); lld v=power(y,p-m-1,p);//a^m*v=1(mod p)p is prime=>v=.... lld e=1; hash[1]=m+1; for(lld i=1;i<=m;i++){ e=(e*y)%p; if(!hash[e])hash[e]=i; } lld ans=-1; for(lld i=0;i<m;i++){ lld j=hash[z]; if(j){ if(j==m+1)j=0; ans=i*m+j; break; } z=(z*v)%p;// } hash.clear(); if(ans==-1)cout<<"Orz, I cannot find x!"<<endl; else cout<<ans<<endl; } int main(){ cin>>t>>k; while(t--){ cin>>y>>z>>p; if(k==1)work1(); if(k==2)work2(); if(k==3)work3(); } return 0; }