题解P2485 [SDOI2011]计算器
RootMirzayanov · · 个人记录
题目传送门
这道题主要可以分解成三个小问题。
1.求 y^z\bmod p 的值
很明显的快速幂模板,不会请见这里。
算法思路:通过指数
当然,每一步进行取模运算也是可以的,依靠公式
很简单,代码如下:
int qmi(int y, int z, int p){
int ans = 1;
while(z > 0){
if(z&1){
ans = ans * y % p;
}
y = y * y % p;
z>>=1;
}
return ans;
}
//既然是快速幂,快速的位运算当然少不了qwq
2.求方程 xy\equiv z\pmod p 的最小非负整数解 x
原式可以化成
又由原式易知 Orz, I cannot find x!。
算法思路:与 GCD 相同,代特殊解
难度不大,不过转化这步是关键点。
扩欧函数代码如下:
int x = 0, y = 0;
void exgcd(int a, int b, int &x, int &y){
if(b == 0){
x = 1;
y = 0;
return;
}
exgcd(b, a % b, x, y);
int z = x;
x = y;
y = z - y * (a / b);
}
//x即为所求值
3.求方程 y^x\equiv z\pmod p 的最小非负整数解 x
很明显的百度搜索谷歌搜索 BSGS 算法模板,不会请见这里
这里详细的说一下 BSGS。
首先,令
即
移项可得
接下来就是 BSGS 算法:
1.从 0-m 的范围枚举 j, 将
2.从 1-m 的范围枚举 i, 从 Hash表找第一个满足方程
此时有解
当枚举无解时,返回Orz, I cannot find x!
这一问是铸就这道题是蓝题的关键。
详细请看代码:
int bsgs(int y,int z,int p) {
map<int,int> hash;
hash.clear();
z%=p;
int m = sqrt(p) + 1;
for(int i = 0;i < m;i++){
hash[(int)z * qmi(y,i,p) % p] = i;
}
a = qmi(y,m,p);
if(!y) return z==0?1:-1;
for(int i = 1;i <= m;i++){
int val = qmi(y,i,p);
int j = hash.find(val)==hash.end()?-1:hash[val];
if(j >= 0 && i * m - j >= 0) return i * m - j;
}
return -1;
}
题解代码可以将上列代码整合,所以不必提供。(逃