本文主要是介绍「题解」 [CQOI2018]破解D-H协议,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前言
人生中第一道紫题,写一篇题解纪念一下。
BSGS
BSGS(拔山盖世,北上广深 )是什么呢?
它是一种能够在 O ( n ) O(\sqrt n\space) O(n )的时间复杂度内求解类似于 a x ≡ b ( m o d p ) a^x \equiv b \pmod{p} ax≡b(modp)的算法。
首先,我们设 x = i p − j x=i\sqrt p-j x=ip−j,其中 i , j ∈ [ 0 , p ] i,j\in [0,\sqrt p\space] i,j∈[0,p ]
那么这个式子就变成了 a i p − j ≡ b ( m o d p ) a^{i\sqrt p-j} \equiv b\pmod p aip−j≡b(modp)
两边同时乘上 a j a^j aj,很显然,等式变成了
a i p ≡ b a j ( m o d p ) a^{i\sqrt p} \equiv ba^j\pmod p aip≡baj(modp)
到了这一步,我们就可以先枚举 j j j,每次把 b a j m o d p ba^j\bmod p bajmodp存入哈希表。
然后再枚举 i i i,在哈希表中查找 a i p a^{i\sqrt p} aip,如果找到了,就说明这个等式成立, x x x就应该是 i p − j i\sqrt p-j ip−j,如果枚举完了也没找着,就说说明这个等式不成立。
在这个过程中,我们仅仅枚举了两次,时间复杂度只有区区的 O ( n ) O(\sqrt n\space) O(n )
题目大意
看起来这个题目很复杂,但其实就是一个BSGS的模板。
简化一下题意,题目告诉你 g a m o d p g^a\bmod p gamodp和 g b m o d p g^b\bmod p gbmodp,让你求 g a b m o d p g^{ab}\bmod p gabmodp。
观察一下,我们发现
g a b m o d p g^{ab}\bmod p gabmodp = ( g a ) b m o d p =(g^a)^b\bmod p =(ga)bmodp = ( g a m o d p ) b m o d p =(g^a\bmod p)^b\bmod p =(gamodp)bmodp = A b m o d p = A^b\bmod p =Abmodp
也就是说,只要我们把 b b b求出来,那就万事大吉了。
那么如何求 b b b呢?
观察发现:
B = g b m o d P B=g^b\bmod P B=gbmodP B ≡ g b ( m o d P ) B \equiv g^b\pmod P B≡gb(modP) g b ≡ B ( m o d P ) g^b \equiv B\pmod P gb≡B(modP)
这不就是BSGS的模板吗?
我们可以用BSGS求出 b b b,然后把用 b b b求出 A b m o d p A^b\bmod p Abmodp。
有了这个思路,我们就可以开始写代码了!
代码:
#include <bits/stdc++.h>
using namespace std;
int g,n,p;//在最开始就定义三个全局变量
int qpow(int a,int b){//快速幂模板int res=1;while(b){if(b&1) res=(a*res)%p;a=(a*a)%p;b>>=1;}return res;
}
int BSGS(int b){map<int,int>m;//哈希表可以用map代替int t=ceil(sqrt(p));//记得要向上取整for(int i=1;i<=t;i++) m[b*qpow(g,i)%p]=i;//枚举j,存入哈希表中for(int i=1;i<=t;i++){int k=qpow(g,i*t)%p;if(m[k]) return i*t-m[k];//如果在哈希表中找到了这个值,就说明找到了b}return -1;//如果没有找到,就说明无解
}int main(){cin>>g>>p>>n;for(int i=1;i<=n;i++){int A,B;cin>>A>>B;int b=BSGS(B);//用BSGS求出bcout<<qpow(A,b)%p<<endl;//用快速幂求出K}return 0;
}
如果把这份代码提交到洛谷上,那么就会出现
万紫千红的场面。
我们可以尝试着开longlong。
#define int long long
提交后发现
WA没了,就变成了tle。
我们可以使用printf
和scanf
。
优化了却没有完全优化。
抱着侥幸的心理,我开了O2,结果发现。
这玄学的数据!
完整代码(记得开O2):
#include <bits/stdc++.h>
#define int long long
using namespace std;
int g,n,p;//在最开始就定义三个全局变量
int qpow(int a,int b){//快速幂模板int res=1;while(b){if(b&1) res=(a*res)%p;a=(a*a)%p;b>>=1;}return res;
}
int BSGS(int b){map<int,int>m;//哈希表可以用map代替int t=ceil(sqrt(p));//记得要向上取整for(int i=1;i<=t;i++) m[b*qpow(g,i)%p]=i;//枚举j,存入哈希表中for(int i=1;i<=t;i++){int k=qpow(g,i*t)%p;if(m[k]) return i*t-m[k];//如果在哈希表中找到了这个值,就说明找到了b}return -1;//如果没有找到,就说明无解
}signed main(){scanf("%lld%lld%lld",&g,&p,&n);for(int i=1;i<=n;i++){int A,B;scanf("%lld%lld",&A,&B);int b=BSGS(B);//用BSGS求出bprintf("%lld\n",qpow(A,b)%p);//用快速幂求出K}return 0;
}
这篇关于「题解」 [CQOI2018]破解D-H协议的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!