您的位置:首页 > 其它

【SDOI2011】【BZOJ】【P2242】【计算器】【题解】【快速幂+扩展欧几里得+高次同余方程/BSGS】

2014-02-07 15:20 501 查看
传送门: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bzoj