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

来源:互联网 发布:淘宝登录限制怎么办 编辑:程序博客网 时间:2024/04/29 04:53

传送门: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:zkyOJ:BZOJIndex:2242Language: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;}



0 0
原创粉丝点击