【bzoj2242】[SDOI2011]计算器 EXgcd+BSGS
题目描述
你被要求设计一个计算器完成以下三项任务:
1、给定y,z,p,计算Y^Z Mod P 的值;
2、给定y,z,p,计算满足xy≡ Z ( mod P )的最小非负整数;
3、给定y,z,p,计算满足Y^x ≡ Z ( mod P)的最小非负整数。
输入
输入包含多组数据。
第一行包含两个正整数T,K分别表示数据组数和询问类型(对于一个测试点内的所有数据,询问类型相同)。
以下行每行包含三个正整数y,z,p,描述一个询问。
输出
对于每个询问,输出一行答案。对于询问类型2和3,如果不存在满足条件的,则输出“Orz, I cannot find x!”,注意逗号与“I”之间有一个空格。
样例输入
【样例输入1】
3 1
2 1 3
2 2 3
2 3 3
【样例输入2】
3 2
2 1 3
2 2 3
2 3 3
样例输出
【样例输出1】
2
1
2
【样例输出2】
2
1
0
题解
EXgcd+BSGS
第一问直接快速幂。
第二问需要将xy≡z(mod p)转化为xy+tp=z,进而用EXgcd求解。
第三问是裸的BSGS。
根据费马小定理可知如果有解,答案一定小于p。
设m=√p(向上取整),再设x=km+b,其中k<m,b<m。
那么就有y^(km+b)≡z(mod p),即y^b≡z/y^km(mod p)。
于是我们可以将所有的y^b mod p加入到map中,然后枚举k,求出z/y^km,看是否有相同的值在map中即可。
本题特判比较多,具体详见代码。
#include <cstdio> #include <cmath> #include <map> using namespace std; typedef long long ll; map<ll , ll> f; map<ll , ll>::iterator it; ll pow(ll x , ll y , ll mod) { ll ans = 1; while(y) { if(y & 1) ans = ans * x % mod; x = x * x % mod , y >>= 1; } return ans; } ll gcd(ll a , ll b) { return b ? gcd(b , a % b) : a; } void exgcd(ll a , ll b , ll &x , ll &y) { if(!b) { x = 1 , y = 0; return; } exgcd(b , a % b , x , y); ll t = x; x = y , y = t - a / b * y; } int main() { int T , k; scanf("%d%d" , &T , &k); while(T -- ) { ll y , z , p; scanf("%lld%lld%lld" , &y , &z , &p); switch(k) { case 1: printf("%lld\n" , pow(y , z , p)); break; case 2: { y %= p , z %= p; ll t = gcd(y , p) , x1 , x2; if(z % t != 0) { printf("Orz, I cannot find x!\n"); break; } y /= t , p /= t , z /= t , exgcd(y , p , x1 , x2) , x1 *= z; while(x1 < 0) x1 += p; while(x1 - p >= 0) x1 -= p; printf("%lld\n" , x1); break; } default: { y %= p , z %= p; if(!y) { if(!z) printf("1\n"); else printf("Orz, I cannot find x!\n"); break; } ll m = (ll)ceil(sqrt(p)) , i , flag = 0 , t = 1 , temp; f.clear(); for(i = 0 ; i < m ; i ++ ) { if(f.find(t) == f.end()) f[t] = i; t = t * y % p; } temp = pow(y , p - m - 1 , p) , t = 1; for(i = 0 ; i <= m ; i ++ ) { it = f.find(z * t % p) , t = t * temp % p; if(it != f.end()) { printf("%lld\n" , i * m + it->second) , flag = 1; break; } } if(!flag) printf("Orz, I cannot find x!\n"); } } } return 0; }