【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代码:
文献:
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_2242_[SDOI2011]计算器_快速幂+扩展GCD+BSGS
- BZOJ_P2242&Codevs_P1565[SDOI2011]计算器(快速幂+扩展欧几里得+BSGS)
- 【快速幂】【扩展欧几里德】【BSGS】【SDOI 2011】【bzoj 2242】计算器
- BZOJ 2242: [SDOI2011]计算器( 快速幂 + 扩展欧几里德 + BSGS )
- 【bzoj2242】[SDOI2011]计算器 数论相关(快速幂+扩展欧几里得+BSGS)
- BZOJ 2242 SDOI2011 计算器 快速幂+扩展欧几里得+BSGS
- 【数论】【快速幂】【扩展欧几里得】【BSGS算法】bzoj2242 [SDOI2011]计算器
- bzoj 2242 [SDOI2011]计算器 快速幂+扩展欧几里得+BSGS
- bzoj 2242: [SDOI2011]计算器 BSGS+快速幂+扩展欧几里德
- 【bzoj2242】[SDOI2011]计算器 快速幂+BSGS
- BZOJ 2242: [SDOI2011]计算器 [快速幂 BSGS]
- bzoj 2242: [SDOI2011]计算器【扩展欧几里得+快速幂+BSGS】
- [SDOI2011] [BZOJ2242] 计算器 - bsgs,快速幂,逆元,map/hash
- BZOJ2242 [SDOI2011]计算器 题解&代码
- BZOJ2242:[SDOI2011]计算器——题解
- BZOJ.2242.[SDOI2011]计算器(扩展欧几里得 BSGS)
- BZOJ 2242 [SDOI2011]计算器 BSGS+高速幂+EXGCD
- 【bzoj 2242】【SDOI2011】计算器 代码(C++)
- BZOJ2242 [SDOI2011]计算器 【BSGS】
- BZOJ-2242-计算器-SDOI2011-BSGS